From 50cdf2c57662f9f69c5615976412f76bfd73311a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 12 Dec 2012 11:03:14 +0100 Subject: [PATCH] MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz --- CREDITS | 9 + MAINTAINERS | 13 + Makefile | 12 +- Makefile-bak-02162007 | 1491 ++++ arch/arm/Kconfig | 146 +- arch/arm/Kconfig-nommu | 17 +- arch/arm/Kconfig.debug | 2 +- arch/arm/Makefile | 33 +- arch/arm/boot/Makefile | 10 +- arch/arm/boot/bootp/bootp.lds | 5 + arch/arm/boot/compressed/Makefile | 17 +- arch/arm/boot/compressed/head-espd_4510b.S | 447 ++ arch/arm/boot/compressed/head-ks8695.S | 5 + arch/arm/boot/compressed/head-p2001.S | 382 + arch/arm/boot/compressed/head-s3c44b0.S | 371 + arch/arm/boot/compressed/head-xscale.S | 99 + arch/arm/boot/compressed/head.S | 417 +- arch/arm/boot/compressed/head.S-bak-06072007 | 851 +++ arch/arm/boot/compressed/misc.c | 4 + arch/arm/common/sa1111.c | 16 + arch/arm/configs/EM1220_defconfig | 980 +++ arch/arm/configs/EM1240_defconfig | 920 +++ arch/arm/configs/GDB_ARMulator_defconfig | 481 ++ arch/arm/configs/UC7110_defconfig | 932 +++ arch/arm/configs/UC7112_defconfig | 978 +++ arch/arm/configs/atmel_defconfig | 481 ++ arch/arm/configs/espd_4510b_defconfig | 648 ++ arch/arm/configs/ks8695_config | 648 ++ arch/arm/configs/lpc22xx_defconfig | 451 ++ arch/arm/configs/p2001_defconfig | 633 ++ arch/arm/configs/s3c24a0_mmu_defconfig | 522 ++ arch/arm/configs/s3c24a0_nommu_defconfig | 518 ++ arch/arm/configs/s3c3410_defconfig | 469 ++ arch/arm/configs/s3c44b0x_defconfig | 618 ++ arch/arm/configs/s5c7375_defconfig | 482 ++ arch/arm/kernel/Makefile | 2 + arch/arm/kernel/armksyms.c | 9 + arch/arm/kernel/entry-common.S | 14 + arch/arm/kernel/head-nommu.S | 31 +- arch/arm/kernel/head.S | 3 + arch/arm/kernel/initrd-mtd.c | 55 + arch/arm/kernel/process.c | 39 +- arch/arm/kernel/setup.c | 2 + arch/arm/kernel/sys_arm.c | 4 +- arch/arm/kernel/traps.c | 10 + arch/arm/mach-adifcc/Kconfig | 30 + arch/arm/mach-atmel/Kconfig | 61 + arch/arm/mach-atmel/Makefile | 1 + arch/arm/mach-atmel/Makefile.boot | 2 + arch/arm/mach-atmel/arch.c | 38 + arch/arm/mach-atmel/head.S | 83 + arch/arm/mach-atmel/irq.c | 211 + arch/arm/mach-atmel/time.c | 104 + arch/arm/mach-espd_4510b/Kconfig | 26 + arch/arm/mach-espd_4510b/Makefile | 7 + arch/arm/mach-espd_4510b/Makefile.boot | 4 + arch/arm/mach-espd_4510b/arch.c | 43 + arch/arm/mach-espd_4510b/dma.c | 26 + arch/arm/mach-espd_4510b/head.S | 96 + arch/arm/mach-espd_4510b/irq.c | 122 + arch/arm/mach-espd_4510b/mm.c | 17 + arch/arm/mach-espd_4510b/time.c | 118 + arch/arm/mach-integrator/integrator_cp.c | 20 +- arch/arm/mach-ixp4xx/Kconfig | 97 +- arch/arm/mach-ixp4xx/Makefile | 17 + arch/arm/mach-ixp4xx/common-pci.c | 2 + arch/arm/mach-ixp4xx/common.c | 8 +- arch/arm/mach-ixp4xx/coyote-setup.c | 1 + arch/arm/mach-ixp4xx/ess710-pci.c | 75 + arch/arm/mach-ixp4xx/sg-setup.c | 253 + arch/arm/mach-ixp4xx/sg5xx-pci.c | 59 + arch/arm/mach-ixp4xx/sg720-pci.c | 98 + arch/arm/mach-ks8695/Kconfig | 55 + arch/arm/mach-ks8695/Makefile | 7 + arch/arm/mach-ks8695/Makefile.boot | 3 + arch/arm/mach-ks8695/arch.c | 117 + arch/arm/mach-ks8695/irq.c | 71 + arch/arm/mach-ks8695/mm.c | 50 + arch/arm/mach-ks8695/pci.c | 217 + arch/arm/mach-ks8695/time.c | 79 + arch/arm/mach-lpc22xx/Kconfig | 44 + arch/arm/mach-lpc22xx/Makefile | 8 + arch/arm/mach-lpc22xx/arch.c | 47 + arch/arm/mach-lpc22xx/head.S | 158 + arch/arm/mach-lpc22xx/irq.c | 137 + arch/arm/mach-lpc22xx/time.c | 83 + arch/arm/mach-moxart/Kconfig | 35 + arch/arm/mach-moxart/Makefile | 21 + arch/arm/mach-moxart/ahb_dma.c | 214 + arch/arm/mach-moxart/apb_dma.c | 267 + arch/arm/mach-moxart/arch.c | 233 + arch/arm/mach-moxart/cpe_dma.c | 253 + arch/arm/mach-moxart/debug.c | 34 + arch/arm/mach-moxart/debug_cpe.c | 55 + arch/arm/mach-moxart/dma.h | 197 + arch/arm/mach-moxart/entry-macro.S | 42 + arch/arm/mach-moxart/ftpci.c | 278 + arch/arm/mach-moxart/gpio.c | 181 + arch/arm/mach-moxart/head.S | 91 + arch/arm/mach-moxart/irq.c | 335 + arch/arm/mach-moxart/irq.c-bak-07312007 | 317 + arch/arm/mach-moxart/pci.c | 409 ++ arch/arm/mach-moxart/timer.c | 193 + arch/arm/mach-p2001/Kconfig | 61 + arch/arm/mach-p2001/Makefile | 9 + arch/arm/mach-p2001/Makefile.boot | 3 + arch/arm/mach-p2001/arch.c | 94 + arch/arm/mach-p2001/entry-macro.S | 168 + arch/arm/mach-p2001/head.S | 94 + arch/arm/mach-p2001/irq.c | 164 + arch/arm/mach-p2001/p2001_cpufreq.c | 286 + arch/arm/mach-p2001/time.c | 273 + arch/arm/mach-s3c2410/Makefile | 2 +- arch/arm/mach-s3c24a0/Kconfig | 13 + arch/arm/mach-s3c24a0/Makefile | 30 + arch/arm/mach-s3c24a0/Makefile.boot | 3 + arch/arm/mach-s3c24a0/clocks.c | 117 + arch/arm/mach-s3c24a0/generic.c | 41 + arch/arm/mach-s3c24a0/generic.h | 14 + arch/arm/mach-s3c24a0/head.S | 172 + arch/arm/mach-s3c24a0/irq.c | 313 + arch/arm/mach-s3c24a0/leds-smdk.c | 121 + arch/arm/mach-s3c24a0/leds.c | 30 + arch/arm/mach-s3c24a0/leds.h | 7 + arch/arm/mach-s3c24a0/registers.c | 261 + arch/arm/mach-s3c24a0/smdk.c | 217 + arch/arm/mach-s3c24a0/time.c | 248 + arch/arm/mach-s3c3410/Kconfig | 33 + arch/arm/mach-s3c3410/Makefile | 7 + arch/arm/mach-s3c3410/arch.c | 54 + arch/arm/mach-s3c3410/dma.c | 26 + arch/arm/mach-s3c3410/head.S | 69 + arch/arm/mach-s3c3410/irq.c | 130 + arch/arm/mach-s3c3410/mm.c | 21 + arch/arm/mach-s3c3410/time.c | 95 + arch/arm/mach-s3c44b0x/Kconfig | 45 + arch/arm/mach-s3c44b0x/Makefile | 8 + arch/arm/mach-s3c44b0x/Makefile.boot | 2 + arch/arm/mach-s3c44b0x/arch.c | 106 + arch/arm/mach-s3c44b0x/cache.S | 35 + arch/arm/mach-s3c44b0x/dma.c | 22 + arch/arm/mach-s3c44b0x/driver/Kconfig | 23 + arch/arm/mach-s3c44b0x/driver/Makefile | 10 + arch/arm/mach-s3c44b0x/driver/console.c | 41 + arch/arm/mach-s3c44b0x/driver/led.c | 28 + arch/arm/mach-s3c44b0x/driver/rtl8019.c | 417 ++ arch/arm/mach-s3c44b0x/driver/rtl8019.h | 55 + arch/arm/mach-s3c44b0x/head.S | 73 + arch/arm/mach-s3c44b0x/irq.c | 142 + arch/arm/mach-s3c44b0x/mm.c | 18 + arch/arm/mach-s3c44b0x/time.c | 104 + arch/arm/mach-s5c7375/Kconfig | 3 + arch/arm/mach-s5c7375/Makefile | 7 + arch/arm/mach-s5c7375/Makefile.boot | 2 + arch/arm/mach-s5c7375/arch.c | 55 + arch/arm/mach-s5c7375/dma.c | 39 + arch/arm/mach-s5c7375/head.S | 162 + arch/arm/mach-s5c7375/irq.c | 147 + arch/arm/mach-s5c7375/time.c | 103 + arch/arm/mm/Kconfig | 32 +- arch/arm/mm/Kconfig-bak-03032007 | 627 ++ arch/arm/mm/Makefile | 9 +- arch/arm/mm/abort-ev0.S | 37 + arch/arm/mm/abort-ev0t.S | 38 + arch/arm/mm/cache-v0.S | 132 + arch/arm/mm/cache-v3.S | 6 + arch/arm/mm/cache-v4.S | 6 +- arch/arm/mm/consistent-nommu.c | 212 + arch/arm/mm/copypage-v4wb.S | 63 + arch/arm/mm/fault.c | 152 +- arch/arm/mm/flush.c | 6 + arch/arm/mm/nommu.c | 24 +- arch/arm/mm/proc-arm720.S | 4 + arch/arm/mm/proc-arm740.S | 330 +- arch/arm/mm/proc-arm7tdmi.S | 216 +- arch/arm/mm/proc-arm922.S | 200 +- arch/arm/mm/proc-arm925.S | 7 +- arch/arm/mm/proc-arm940.S | 587 +- arch/arm/mm/proc-arm946.S | 639 +- arch/arm/mm/proc-arm9tdmi.S | 211 +- arch/arm/mm/proc-lpc22xx.S | 291 + arch/arm/mm/proc-s3c4510b.S | 387 + arch/arm/mm/proc-syms.c | 5 + arch/arm/mm/proc-xsc3.S | 3 + arch/arm/mm/proc-xscale.S | 3 + arch/arm/tools/mach-types | 4 +- arch/i386/boot/bootsect.S | 391 +- arch/i386/boot/compressed/head.S | 6 + arch/i386/boot/compressed/misc.c | 5 + arch/i386/boot/setup.S | 276 +- arch/m68knommu/Kconfig | 12 +- arch/m68knommu/kernel/process.c | 34 +- arch/m68knommu/kernel/setup.c | 9 +- arch/m68knommu/kernel/sys_m68k.c | 23 +- arch/m68knommu/kernel/traps.c | 13 +- arch/m68knommu/platform/5307/head.S | 20 + arch/m68knommu/platform/5307/ints.c | 1 - arch/m68knommu/platform/5307/timers.c | 16 +- arch/m68knommu/platform/532x/spi-mcf532x.c | 176 + arch/m68knommu/platform/532x/usb-mcf532x.c | 170 + arch/m68knommu/platform/68360/config.c | 2 +- arch/m68knommu/platform/68360/head-ram.S | 3 +- arch/m68knommu/platform/68VZ328/screen.xbm | 804 +++ arch/m68knommu/platform/68VZ328/xbm2lcd.pl | 6 + arch/nios2nommu/ChangeLog | 4 + arch/nios2nommu/Kconfig | 397 ++ arch/nios2nommu/Kconfig.debug | 35 + arch/nios2nommu/Makefile | 181 + arch/nios2nommu/boot/Makefile | 17 + arch/nios2nommu/boot/compressed/Makefile | 36 + arch/nios2nommu/boot/compressed/head.S | 100 + arch/nios2nommu/boot/compressed/install.sh | 57 + arch/nios2nommu/boot/compressed/misc.c | 208 + arch/nios2nommu/boot/compressed/nios2_sio.c | 57 + arch/nios2nommu/defconfig | 690 ++ arch/nios2nommu/drivers/Kconfig | 24 + arch/nios2nommu/drivers/Makefile | 8 + arch/nios2nommu/drivers/altfb.c | 234 + arch/nios2nommu/drivers/altps2.c | 193 + arch/nios2nommu/drivers/i2c-gpio.c | 166 + arch/nios2nommu/drivers/pci/Kconfig | 6 + arch/nios2nommu/drivers/pci/Makefile | 8 + arch/nios2nommu/drivers/pci/altpci.c | 204 + arch/nios2nommu/drivers/pci/pci-auto.c | 559 ++ arch/nios2nommu/drivers/pci/pci.c | 151 + arch/nios2nommu/drivers/pci/setup-irq.c | 1 + arch/nios2nommu/kernel/ChangeLog | 27 + arch/nios2nommu/kernel/Makefile | 22 + arch/nios2nommu/kernel/asm-offsets.c | 201 + arch/nios2nommu/kernel/dma.c | 342 + arch/nios2nommu/kernel/entry.S | 898 +++ arch/nios2nommu/kernel/head.S | 228 + arch/nios2nommu/kernel/init_task.c | 69 + arch/nios2nommu/kernel/io.c | 143 + arch/nios2nommu/kernel/irq.c | 245 + arch/nios2nommu/kernel/module.c | 173 + arch/nios2nommu/kernel/nios2_ksyms.c | 124 + arch/nios2nommu/kernel/nios_gdb_stub.c | 1456 ++++ arch/nios2nommu/kernel/nios_gdb_stub.h | 105 + arch/nios2nommu/kernel/nios_gdb_stub_io.c | 39 + arch/nios2nommu/kernel/nios_gdb_stub_isr.S | 99 + arch/nios2nommu/kernel/pio.c | 154 + arch/nios2nommu/kernel/process.c | 577 ++ arch/nios2nommu/kernel/ptrace.c | 352 + arch/nios2nommu/kernel/semaphore.c | 155 + arch/nios2nommu/kernel/setup.c | 664 ++ arch/nios2nommu/kernel/signal.c | 738 ++ arch/nios2nommu/kernel/start.c | 558 ++ arch/nios2nommu/kernel/sys_nios2.c | 246 + arch/nios2nommu/kernel/syscalltable.S | 322 + arch/nios2nommu/kernel/time.c | 191 + arch/nios2nommu/kernel/traps.c | 178 + arch/nios2nommu/kernel/usb.c | 354 + arch/nios2nommu/lib/Makefile | 17 + arch/nios2nommu/lib/checksum.c | 73 + arch/nios2nommu/lib/memcpy.c | 62 + arch/nios2nommu/lib/string.c | 180 + arch/nios2nommu/mm/Makefile | 12 + arch/nios2nommu/mm/dma-noncoherent.c | 373 + arch/nios2nommu/mm/extable.c | 29 + arch/nios2nommu/mm/init.c | 233 + arch/nios2nommu/mm/ioremap.c | 65 + arch/nios2nommu/mm/memory.c | 225 + arch/nios2nommu/scripts/PTF/PTFParser.pm | 873 +++ arch/nios2nommu/scripts/PTF/PTFParser.yp | 178 + arch/nios2nommu/scripts/PTF/PTFSection.pm | 81 + arch/nios2nommu/scripts/PTF/SystemPTF.pm | 149 + arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm | 2 + arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm | 89 + arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm | 267 + arch/nios2nommu/scripts/gen_nios2_system.h.pl | 314 + arch/nios2nommu/scripts/hwselect.pl | 166 + .../scripts/nios2_system.h/BasicModule.pm | 267 + .../scripts/nios2_system.h/altera_avalon_cf.pm | 18 + .../nios2_system.h/altera_avalon_jtag_uart.pm | 18 + .../nios2_system.h/altera_avalon_lan91c111.pm | 38 + .../scripts/nios2_system.h/altera_avalon_pio.pm | 46 + .../scripts/nios2_system.h/altera_avalon_spi.pm | 30 + .../scripts/nios2_system.h/altera_avalon_sysid.pm | 18 + .../scripts/nios2_system.h/altera_avalon_timer.pm | 46 + .../scripts/nios2_system.h/altera_avalon_uart.pm | 44 + .../nios2_system.h/mtip_avalon_10_100_mac.pm | 18 + .../scripts/nios2_system.h/mtx_avalon_dm9000.pm | 18 + .../scripts/nios2_system.h/mtx_avalon_isp1161a1.pm | 18 + .../nios2_system.h/opencores_ethernet_mac.pm | 18 + .../scripts/nios2_system.h/opencores_i2c.pm | 18 + arch/sh/Kconfig | 35 + arch/sh/Makefile | 2 +- arch/sh/boards/se/770x/setup.c | 2 +- arch/sh/boards/snapgear/Makefile | 2 +- arch/sh/boards/snapgear/rtc.c | 1 + arch/sh/boards/snapgear/setup.c | 116 +- arch/sh/drivers/pci/ops-snapgear.c | 2 +- arch/sh/drivers/pci/pci-auto.c | 6 +- arch/sh/kernel/head.S | 16 +- arch/sh/kernel/process.c | 6 +- arch/sh/kernel/setup.c | 76 +- arch/sh/lib/checksum.S | 2 +- arch/sh/lib/memchr.S | 2 +- arch/sh/lib/memcpy.S | 2 +- arch/sh/lib/memmove.S | 2 +- arch/sh/lib/memset.S | 2 +- arch/sh/lib/strlen.S | 2 +- arch/um/Kconfig.arch | 1 + arch/um/kernel/skas/clone.c | 4 + arch/um/os-Linux/Makefile | 2 +- arch/v850/lib/checksum.c | 2 +- block/as-iosched.c | 17 + block/deadline-iosched.c | 8 + block/elevator.c | 27 + block/ioctl.c | 8 + block/ll_rw_blk.c | 8 + drivers/Makefile | 1 + drivers/block/rd.c | 9 + drivers/char/Kconfig | 101 +- drivers/char/Makefile | 13 + drivers/char/altera_pio_button.c | 280 + drivers/char/fast_timer.c | 169 + drivers/char/gpio.c | 196 + drivers/char/gpio.c-bak-07312007 | 239 + drivers/char/keypad.c | 235 + drivers/char/lcd_16207.c | 132 + drivers/char/lcm0.c | 700 ++ drivers/char/lcm1.c | 768 ++ drivers/char/lcm2.c | 729 ++ drivers/char/lcm3.c | 700 ++ drivers/char/ledman.c | 2189 ++++++ drivers/char/m41t11m6.c | 527 ++ drivers/char/mcf_qspi.c | 857 +++ drivers/char/mcf_qspi.h | 94 + drivers/char/mcfwatchdog.c | 365 + drivers/char/moxalcm.h | 31 + drivers/char/mxser.c | 7381 +++++++++++--------- drivers/char/resetswitch.c | 138 + drivers/char/resetswitch.c-bak-07312007 | 192 + drivers/char/resetswitch.c-old | 147 + drivers/char/rtc.c | 1842 ++--- drivers/char/rtc.c-bak-09052007 | 461 ++ drivers/char/rtc.c-old | 1380 ++++ drivers/char/snapdog.c | 459 ++ drivers/char/watchdog/Kconfig | 37 + drivers/char/watchdog/Makefile | 6 + drivers/char/watchdog/avalonwdt.c | 220 + drivers/char/watchdog/ixp4xx_wdt.c | 20 +- drivers/char/watchdog/m5272_wdt.c | 228 + drivers/char/watchdog/uc7110wdt.c | 505 ++ drivers/hwmon/hwmon-vid.c | 2 + drivers/hwmon/lm87.c | 4 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-iop3xx.c | 1 + drivers/i2c/busses/i2c-ixp4xx.c | 57 +- drivers/i2c/busses/i2c-mcf.c | 556 ++ drivers/i2c/busses/i2c-mcf.h | 52 + drivers/i2c/chips/Kconfig | 12 + drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/m41t11.c | 307 + drivers/ide/Kconfig | 7 + drivers/ide/arm/adi-coyote.c | 104 + drivers/ide/ide-io.c | 6 +- drivers/ide/ide-probe.c | 5 +- drivers/ide/pci/Makefile | 1 + drivers/ide/pci/p20575.c | 227 + drivers/ieee1394/dma.c | 21 + drivers/mmc/Kconfig | 10 + drivers/mmc/Makefile | 1 + drivers/mmc/mmc.c | 16 + drivers/mmc/mmc_block.c | 64 +- drivers/mmc/mmc_sysfs.c | 4 + drivers/mmc/moxasd.c | 736 ++ drivers/mmc/moxasd.c-bak-07122007 | 836 +++ drivers/mmc/moxasd.h | 108 + drivers/mtd/chips/Kconfig | 9 + drivers/mtd/chips/Makefile | 1 + drivers/mtd/chips/cfi_cmdset_0001.c | 11 +- drivers/mtd/chips/cfi_probe.c | 1 + drivers/mtd/chips/chipreg.c | 22 +- drivers/mtd/chips/epcs.c | 205 + drivers/mtd/chips/epcs.h | 79 + drivers/mtd/chips/epcs_low.c | 486 ++ drivers/mtd/chips/jedec_probe.c | 81 + drivers/mtd/devices/docprobe.c | 7 +- drivers/mtd/maps/Kconfig | 149 + drivers/mtd/maps/Makefile | 15 + drivers/mtd/maps/altera.c | 178 + drivers/mtd/maps/avnet5282.c | 108 + drivers/mtd/maps/cobra5272.c | 153 + drivers/mtd/maps/cobra5282.c | 138 + drivers/mtd/maps/cobra5329.c | 91 + drivers/mtd/maps/dm270-flash.c | 230 + drivers/mtd/maps/em1110.c | 102 + drivers/mtd/maps/em1220.c | 103 + drivers/mtd/maps/em1220_dlin.c | 103 + drivers/mtd/maps/em1240.c | 103 + drivers/mtd/maps/em1240_ivtc.c | 104 + drivers/mtd/maps/em1240_mt.c | 103 + drivers/mtd/maps/epcs_map.c | 157 + drivers/mtd/maps/ixp4xx.c | 2 +- drivers/mtd/maps/m520x.c | 241 + drivers/mtd/maps/microtronix.c | 129 + drivers/mtd/maps/nettel.c | 5 +- drivers/mtd/maps/plat-ram.c | 44 +- drivers/mtd/maps/snaparm.c | 827 +++ drivers/mtd/maps/snapgear-uc.c | 435 ++ drivers/mtd/maps/snapgeode.c | 223 + drivers/mtd/maps/uc7101.c | 102 + drivers/mtd/maps/uc7110.c | 111 + drivers/mtd/maps/uc7112.c | 102 + drivers/mtd/maps/uclinux.c | 54 +- drivers/mtd/maps/w311_test.c | 102 + drivers/mtd/maps/w315_ec.c | 102 + drivers/mtd/maps/w321_gl2.c | 103 + drivers/mtd/mtd_blkdevs.c | 12 + drivers/mtd/mtdchar.c | 45 +- drivers/mtd/nand/Kconfig | 7 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/diskonchip.c | 420 +- drivers/mtd/nand/m5329.c | 179 + drivers/net/8139cp.c | 271 +- drivers/net/8139too.c | 22 +- drivers/net/8390.c | 32 +- drivers/net/8390.h | 6 + drivers/net/Kconfig | 59 +- drivers/net/Makefile | 4 +- drivers/net/arm/Kconfig | 34 + drivers/net/arm/Makefile | 3 + drivers/net/arm/eth_moxa.c | 904 +++ drivers/net/arm/eth_moxa.h | 359 + drivers/net/arm/eth_s3c4510b.c | 512 ++ drivers/net/arm/eth_s3c4510b.h | 301 + drivers/net/arm/p2001_eth.c | 934 +++ drivers/net/cs89x0.c | 122 +- drivers/net/cs89x0_defs.h | 82 + drivers/net/cs89x0_fct.h | 34 + drivers/net/fec.c | 23 + drivers/net/ks8695/Makefile | 13 + drivers/net/ks8695/ks8695_cache.c | 280 + drivers/net/ks8695/ks8695_cache.h | 48 + drivers/net/ks8695/ks8695_chipdef.h | 440 ++ drivers/net/ks8695/ks8695_drv.h | 204 + drivers/net/ks8695/ks8695_fxhw.c | 2753 ++++++++ drivers/net/ks8695/ks8695_fxhw.h | 46 + drivers/net/ks8695/ks8695_ioctrl.h | 163 + drivers/net/ks8695/ks8695_kcompat.h | 316 + drivers/net/ks8695/ks8695_main.c | 4400 ++++++++++++ drivers/net/mtip1000.c | 2485 +++++++ drivers/net/mtip1000.h | 408 ++ drivers/net/ne.c | 143 +- drivers/net/ns83865phy.h | 98 + drivers/net/open_eth.c | 2209 ++++++ drivers/net/open_eth.h | 179 + drivers/net/r8169.c | 81 +- drivers/net/slip.c | 15 + drivers/net/smc9194.c | 781 ++- drivers/net/smc9194.h | 51 + drivers/net/stdphy.h | 79 + drivers/net/tdk78phy.h | 44 + drivers/pci/pci.c | 2 + drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-ds1302.c | 234 + drivers/rtc/rtc-sh.c | 14 +- drivers/scsi/scsi.c | 4 + drivers/scsi/scsi_lib.c | 4 + drivers/scsi/sd.c | 16 + drivers/serial/8250.c | 104 +- drivers/serial/Kconfig | 245 + drivers/serial/Makefile | 9 + drivers/serial/NIOSserial.c | 1317 ++++ drivers/serial/NIOSserial.h | 123 + drivers/serial/altera_juart.c | 505 ++ drivers/serial/dcc.c | 550 ++ drivers/serial/mcf.c | 828 +++ drivers/serial/mcfserial.c | 65 +- drivers/serial/p2001_uart.c | 720 ++ drivers/serial/serial_atmel.c | 1882 +++++ drivers/serial/serial_atmel.h | 124 + drivers/serial/serial_core.c | 67 + drivers/serial/serial_dm270.c | 944 +++ drivers/serial/serial_ks8695.c | 569 ++ drivers/serial/serial_s3c24a0.c | 595 ++ drivers/serial/serial_s3c4510b.c | 637 ++ drivers/serial/sh-sci.c | 158 + drivers/spi/DS1305RTC.c | 252 + drivers/spi/Kconfig | 23 + drivers/spi/Makefile | 3 + drivers/spi/mcf_qspi.c | 1107 +++ drivers/usb/Kconfig | 1 + drivers/usb/core/urb.c | 10 + drivers/usb/host/ehci-hcd.c | 13 + drivers/usb/host/ehci-moxaart.c | 237 + drivers/usb/host/ehci.h | 113 + drivers/usb/net/Kconfig | 2 +- drivers/video/Kconfig | 52 + drivers/video/Makefile | 2 + drivers/video/dm270fb.c | 1548 ++++ drivers/video/dm270fb.h | 149 + drivers/video/m532xfb.c | 615 ++ fs/Kconfig | 109 +- fs/Makefile | 4 + fs/binfmt_flat.c | 37 +- fs/block_dev.c | 32 + fs/buffer.c | 74 + fs/char_dev.c | 20 + fs/cramfs/inode.c | 77 +- fs/exec.c | 106 + fs/ext2/dir.c | 24 + fs/ext2/inode.c | 6 + fs/ext3/inode.c | 42 + fs/fat/inode.c | 13 + fs/fifo.c | 16 + fs/file_table.c | 5 + fs/hfs/inode.c | 4 + fs/hfsplus/inode.c | 4 + fs/inode.c | 14 + fs/jbd/commit.c | 4 + fs/jbd/journal.c | 6 + fs/jffs2/background.c | 79 + fs/jffs2/file.c | 16 + fs/jffs2/nodemgmt.c | 15 + fs/jffs2/super.c | 1 + fs/jffs2/xattr.h | 8 + fs/jfs/inode.c | 4 + fs/libfs.c | 4 + fs/lockd/mon.c | 6 + fs/mpage.c | 28 + fs/namei.c | 2 + fs/nfs/file.c | 8 + fs/nfs/pagelist.c | 4 + fs/nfs/read.c | 8 + fs/nfs/write.c | 24 + fs/ocfs2/aops.c | 4 + fs/partitions/ldm.c | 3 + fs/pipe.c | 57 + fs/proc/base.c | 4 +- fs/reiserfs/inode.c | 8 +- fs/splice.c | 16 + fs/squashfs/LzmaDecode.c | 648 ++ fs/squashfs/LzmaDecode.h | 85 + fs/squashfs/LzmaWrapper.c | 90 + fs/squashfs/LzmaWrapper.h | 13 + fs/squashfs/Makefile | 10 + fs/squashfs/inode.c | 1846 +++++ fs/xfs/linux-2.6/xfs_aops.c | 4 + include/asm-arm/arch-atmel/at91x40.h | 57 + include/asm-arm/arch-atmel/at91x63.h | 73 + include/asm-arm/arch-atmel/dma.h | 25 + include/asm-arm/arch-atmel/entry-macro.S | 44 + include/asm-arm/arch-atmel/hardware.h | 256 + include/asm-arm/arch-atmel/io.h | 40 + include/asm-arm/arch-atmel/irq.h | 22 + include/asm-arm/arch-atmel/irqs.h | 65 + include/asm-arm/arch-atmel/memory.h | 28 + include/asm-arm/arch-atmel/param.h | 6 + include/asm-arm/arch-atmel/system.h | 42 + include/asm-arm/arch-atmel/time.h | 29 + include/asm-arm/arch-atmel/timex.h | 10 + include/asm-arm/arch-atmel/uncompress.h | 43 + include/asm-arm/arch-atmel/vmalloc.h | 35 + include/asm-arm/arch-espd_4510b/dma.h | 28 + include/asm-arm/arch-espd_4510b/entry-macro.S | 27 + include/asm-arm/arch-espd_4510b/hardware.h | 30 + include/asm-arm/arch-espd_4510b/io.h | 67 + include/asm-arm/arch-espd_4510b/irq.h | 27 + include/asm-arm/arch-espd_4510b/irqs.h | 42 + include/asm-arm/arch-espd_4510b/keyboard.h | 21 + include/asm-arm/arch-espd_4510b/memory.h | 23 + include/asm-arm/arch-espd_4510b/param.h | 6 + include/asm-arm/arch-espd_4510b/s3c4510b.h | 255 + include/asm-arm/arch-espd_4510b/system.h | 27 + include/asm-arm/arch-espd_4510b/time.h | 31 + include/asm-arm/arch-espd_4510b/timex.h | 27 + include/asm-arm/arch-espd_4510b/uart.h | 114 + include/asm-arm/arch-espd_4510b/uncompress.c | 69 + include/asm-arm/arch-espd_4510b/uncompress.h | 50 + include/asm-arm/arch-espd_4510b/vmalloc.h | 35 + include/asm-arm/arch-integrator/hardware.h | 27 + include/asm-arm/arch-integrator/memory.h | 10 + include/asm-arm/arch-ixp4xx/fast_timer.h | 53 + include/asm-arm/arch-ixp4xx/hardware.h | 1 + include/asm-arm/arch-ixp4xx/ide.h | 37 + include/asm-arm/arch-ixp4xx/irqs.h | 18 + include/asm-arm/arch-ixp4xx/memory.h | 2 + include/asm-arm/arch-ixp4xx/platform.h | 5 + include/asm-arm/arch-ixp4xx/sg.h | 20 + include/asm-arm/arch-ixp4xx/timex.h | 4 + include/asm-arm/arch-ixp4xx/uncompress.h | 24 +- include/asm-arm/arch-ks8695/debug-macro.S | 37 + include/asm-arm/arch-ks8695/dma.h | 26 + include/asm-arm/arch-ks8695/entry-macro.S | 28 + include/asm-arm/arch-ks8695/fast_timer.h | 56 + include/asm-arm/arch-ks8695/hardware.h | 38 + include/asm-arm/arch-ks8695/io.h | 31 + include/asm-arm/arch-ks8695/irqs.h | 98 + include/asm-arm/arch-ks8695/ks8695-pci.h | 68 + include/asm-arm/arch-ks8695/ks8695-regs.h | 341 + include/asm-arm/arch-ks8695/memory.h | 44 + include/asm-arm/arch-ks8695/param.h | 20 + include/asm-arm/arch-ks8695/system.h | 48 + include/asm-arm/arch-ks8695/timex.h | 26 + include/asm-arm/arch-ks8695/uncompress.h | 53 + include/asm-arm/arch-ks8695/vmalloc.h | 26 + include/asm-arm/arch-lpc22xx/dma.h | 25 + include/asm-arm/arch-lpc22xx/entry-macro.S | 34 + include/asm-arm/arch-lpc22xx/hardware.h | 31 + include/asm-arm/arch-lpc22xx/io.h | 66 + include/asm-arm/arch-lpc22xx/irq.h | 22 + include/asm-arm/arch-lpc22xx/irqs.h | 45 + include/asm-arm/arch-lpc22xx/keyboard.h | 19 + include/asm-arm/arch-lpc22xx/log | 944 +++ include/asm-arm/arch-lpc22xx/lpc22xx.h | 469 ++ include/asm-arm/arch-lpc22xx/memory.h | 23 + include/asm-arm/arch-lpc22xx/param.h | 8 + include/asm-arm/arch-lpc22xx/serial.h | 43 + include/asm-arm/arch-lpc22xx/system.h | 28 + include/asm-arm/arch-lpc22xx/time.h | 23 + include/asm-arm/arch-lpc22xx/timex.h | 26 + include/asm-arm/arch-lpc22xx/vmalloc.h | 35 + include/asm-arm/arch-moxart/cpe_int.h | 8 + include/asm-arm/arch-moxart/cpe_time.h | 86 + include/asm-arm/arch-moxart/dma.h | 173 + include/asm-arm/arch-moxart/entry-macro.S | 42 + include/asm-arm/arch-moxart/ftpci.h | 74 + include/asm-arm/arch-moxart/gpio.h | 38 + include/asm-arm/arch-moxart/hardware.h | 19 + include/asm-arm/arch-moxart/io.h | 16 + include/asm-arm/arch-moxart/irq.h | 88 + include/asm-arm/arch-moxart/irq.h-bak-11212005 | 82 + include/asm-arm/arch-moxart/irqs.h | 9 + include/asm-arm/arch-moxart/memory.h | 56 + include/asm-arm/arch-moxart/moxa-uart.h | 83 + include/asm-arm/arch-moxart/moxa.h | 188 + include/asm-arm/arch-moxart/param.h | 4 + include/asm-arm/arch-moxart/processor.h | 17 + include/asm-arm/arch-moxart/serial.h | 13 + include/asm-arm/arch-moxart/system.h | 36 + include/asm-arm/arch-moxart/time.h | 36 + include/asm-arm/arch-moxart/timex.h | 13 + include/asm-arm/arch-moxart/uncompress.h | 76 + include/asm-arm/arch-p2001/debug-macro.S | 37 + include/asm-arm/arch-p2001/dma.h | 31 + include/asm-arm/arch-p2001/entry-macro.S | 168 + include/asm-arm/arch-p2001/hardware.h | 351 + include/asm-arm/arch-p2001/io.h | 36 + include/asm-arm/arch-p2001/irq.h | 32 + include/asm-arm/arch-p2001/irqs.h | 42 + include/asm-arm/arch-p2001/memory.h | 31 + include/asm-arm/arch-p2001/param.h | 16 + include/asm-arm/arch-p2001/system.h | 32 + include/asm-arm/arch-p2001/timex.h | 17 + include/asm-arm/arch-p2001/uncompress.h | 43 + include/asm-arm/arch-p2001/vmalloc.h | 35 + include/asm-arm/arch-s3c24a0/S3C24A0.h | 1462 ++++ include/asm-arm/arch-s3c24a0/bitfield.h | 116 + include/asm-arm/arch-s3c24a0/clocks.h | 38 + include/asm-arm/arch-s3c24a0/debug-macro.S | 40 + include/asm-arm/arch-s3c24a0/dma.h | 55 + include/asm-arm/arch-s3c24a0/entry-macro.S | 32 + include/asm-arm/arch-s3c24a0/hardware.h | 143 + include/asm-arm/arch-s3c24a0/ide.h | 147 + include/asm-arm/arch-s3c24a0/io.h | 45 + include/asm-arm/arch-s3c24a0/irq.h | 16 + include/asm-arm/arch-s3c24a0/irqs.h | 144 + include/asm-arm/arch-s3c24a0/keyboard.h | 134 + include/asm-arm/arch-s3c24a0/memory.h | 44 + include/asm-arm/arch-s3c24a0/param.h | 11 + include/asm-arm/arch-s3c24a0/s3c24a0-common.h | 35 + include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h | 156 + include/asm-arm/arch-s3c24a0/s3c24a0-key.h | 116 + include/asm-arm/arch-s3c24a0/s3c24a0-machine.h | 223 + include/asm-arm/arch-s3c24a0/s3c24a0_nand.h | 485 ++ include/asm-arm/arch-s3c24a0/smdk.h | 144 + include/asm-arm/arch-s3c24a0/system.h | 31 + include/asm-arm/arch-s3c24a0/time.h | 16 + include/asm-arm/arch-s3c24a0/timex.h | 27 + include/asm-arm/arch-s3c24a0/uncompress-jtag.h | 58 + include/asm-arm/arch-s3c24a0/uncompress.h | 59 + include/asm-arm/arch-s3c24a0/vmalloc.h | 24 + include/asm-arm/arch-s3c3410/dma.h | 25 + include/asm-arm/arch-s3c3410/entry-macro.S | 38 + include/asm-arm/arch-s3c3410/hardware.h | 27 + include/asm-arm/arch-s3c3410/io.h | 67 + include/asm-arm/arch-s3c3410/irq.h | 24 + include/asm-arm/arch-s3c3410/irqs.h | 48 + include/asm-arm/arch-s3c3410/keyboard.h | 21 + include/asm-arm/arch-s3c3410/memory.h | 23 + include/asm-arm/arch-s3c3410/param.h | 6 + include/asm-arm/arch-s3c3410/s3c3410.h | 384 + include/asm-arm/arch-s3c3410/system.h | 29 + include/asm-arm/arch-s3c3410/time.h | 23 + include/asm-arm/arch-s3c3410/timex.h | 27 + include/asm-arm/arch-s3c3410/vmalloc.h | 35 + include/asm-arm/arch-s3c44b0x/dma.h | 19 + include/asm-arm/arch-s3c44b0x/entry-macro.S | 31 + include/asm-arm/arch-s3c44b0x/hardware.h | 35 + include/asm-arm/arch-s3c44b0x/io.h | 63 + include/asm-arm/arch-s3c44b0x/irq.h | 20 + include/asm-arm/arch-s3c44b0x/irqs.h | 37 + include/asm-arm/arch-s3c44b0x/keyboard.h | 16 + include/asm-arm/arch-s3c44b0x/memory.h | 22 + include/asm-arm/arch-s3c44b0x/param.h | 6 + include/asm-arm/arch-s3c44b0x/s3c44b0x.h | 704 ++ include/asm-arm/arch-s3c44b0x/system.h | 25 + include/asm-arm/arch-s3c44b0x/time.h | 7 + include/asm-arm/arch-s3c44b0x/timex.h | 10 + include/asm-arm/arch-s3c44b0x/uncompress.c | 23 + include/asm-arm/arch-s3c44b0x/uncompress.h | 51 + include/asm-arm/arch-s3c44b0x/vmalloc.h | 18 + include/asm-arm/arch-s5c7375/blkmem.h | 25 + include/asm-arm/arch-s5c7375/dma.h | 140 + include/asm-arm/arch-s5c7375/entry-macro.S | 57 + include/asm-arm/arch-s5c7375/hardware.h | 31 + include/asm-arm/arch-s5c7375/io.h | 69 + include/asm-arm/arch-s5c7375/irq.h | 40 + include/asm-arm/arch-s5c7375/irqs.h | 124 + include/asm-arm/arch-s5c7375/memory.h | 28 + include/asm-arm/arch-s5c7375/param.h | 6 + include/asm-arm/arch-s5c7375/s5c7375.h | 384 + include/asm-arm/arch-s5c7375/system.h | 63 + include/asm-arm/arch-s5c7375/time.h | 88 + include/asm-arm/arch-s5c7375/timex.h | 27 + include/asm-arm/arch-s5c7375/uncompress.h | 58 + include/asm-arm/arch-s5c7375/vmalloc.h | 35 + include/asm-arm/byteorder.h | 8 + include/asm-arm/cacheflush.h | 16 + include/asm-arm/cpu-multi32.h | 5 + include/asm-arm/cpu-single.h | 5 + include/asm-arm/fast_timer.h | 1 + include/asm-arm/flat.h | 14 +- include/asm-arm/glue.h | 16 + include/asm-arm/hardware.h | 23 + include/asm-arm/hardware/dcc.h | 49 + include/asm-arm/mach/arch.h | 1 + include/asm-arm/mach/i2c-gpio.h | 24 + include/asm-arm/mmu_context.h | 4 + include/asm-arm/nommu.h | 16 + include/asm-arm/nommu_context.h | 45 + include/asm-arm/proc-fns.h | 2 + include/asm-arm/procinfo.h | 3 + include/asm-arm/ptrace.h | 2 + include/asm-arm/string.h | 4 + include/asm-arm/uaccess-nommu.h | 203 + include/asm-arm/unaligned.h | 22 + include/asm-arm/unistd.h | 6 + include/asm-i386/edd.h | 177 + include/asm-m68knommu/DS1305RTC.h | 82 + include/asm-m68knommu/cs89x0_fct.h | 347 + include/asm-m68knommu/dma-mapping.h | 3 +- include/asm-m68knommu/dma.h | 2 + include/asm-m68knommu/irq.h | 1 + include/asm-m68knommu/m520xsim.h | 12 +- include/asm-m68knommu/m528xsim.h | 3 + include/asm-m68knommu/machdep.h | 8 +- include/asm-m68knommu/mcfqspi.h | 30 + include/asm-m68knommu/rtc.h | 1 + include/asm-m68knommu/scatterlist.h | 2 +- include/asm-m68knommu/ucontext.h | 6 - include/asm-nios2nommu/ChangeLog | 14 + include/asm-nios2nommu/a.out.h | 85 + include/asm-nios2nommu/altera_juart.h | 36 + include/asm-nios2nommu/asm-macros.h | 331 + include/asm-nios2nommu/atomic.h | 146 + include/asm-nios2nommu/auxvec.h | 4 + include/asm-nios2nommu/bitops.h | 11 + include/asm-nios2nommu/bootinfo.h | 2 + include/asm-nios2nommu/bug.h | 4 + include/asm-nios2nommu/bugs.h | 40 + include/asm-nios2nommu/byteorder.h | 38 + include/asm-nios2nommu/cache.h | 36 + include/asm-nios2nommu/cachectl.h | 36 + include/asm-nios2nommu/cacheflush.h | 59 + include/asm-nios2nommu/checksum.h | 320 + include/asm-nios2nommu/cprefix.h | 38 + include/asm-nios2nommu/cpumask.h | 28 + include/asm-nios2nommu/cputime.h | 31 + include/asm-nios2nommu/current.h | 39 + include/asm-nios2nommu/delay.h | 96 + include/asm-nios2nommu/div64.h | 31 + include/asm-nios2nommu/dma-mapping.h | 79 + include/asm-nios2nommu/dma.h | 63 + include/asm-nios2nommu/elf.h | 140 + include/asm-nios2nommu/emergency-restart.h | 6 + include/asm-nios2nommu/entry.h | 187 + include/asm-nios2nommu/errno.h | 6 + include/asm-nios2nommu/fcntl.h | 110 + include/asm-nios2nommu/flat.h | 126 + include/asm-nios2nommu/futex.h | 6 + include/asm-nios2nommu/gpio.h | 11 + include/asm-nios2nommu/hardirq.h | 43 + include/asm-nios2nommu/hdreg.h | 30 + include/asm-nios2nommu/hw_irq.h | 16 + include/asm-nios2nommu/ide.h | 47 + include/asm-nios2nommu/init.h | 22 + include/asm-nios2nommu/io.h | 260 + include/asm-nios2nommu/ioctl.h | 100 + include/asm-nios2nommu/ioctls.h | 103 + include/asm-nios2nommu/ipc.h | 51 + include/asm-nios2nommu/ipcbuf.h | 49 + include/asm-nios2nommu/irq.h | 181 + include/asm-nios2nommu/irq_node.h | 36 + include/asm-nios2nommu/irq_regs.h | 1 + include/asm-nios2nommu/kmap_types.h | 43 + include/asm-nios2nommu/linkage.h | 29 + include/asm-nios2nommu/linux_logo.h | 953 +++ include/asm-nios2nommu/local.h | 28 + include/asm-nios2nommu/mc146818rtc.h | 29 + include/asm-nios2nommu/mman.h | 68 + include/asm-nios2nommu/mmu.h | 36 + include/asm-nios2nommu/mmu_context.h | 57 + include/asm-nios2nommu/module.h | 36 + include/asm-nios2nommu/msgbuf.h | 56 + include/asm-nios2nommu/mutex.h | 9 + include/asm-nios2nommu/namei.h | 36 + include/asm-nios2nommu/ndma.h | 64 + include/asm-nios2nommu/nios.h | 7 + include/asm-nios2nommu/page.h | 123 + include/asm-nios2nommu/param.h | 49 + include/asm-nios2nommu/pci.h | 130 + include/asm-nios2nommu/percpu.h | 30 + include/asm-nios2nommu/pgalloc.h | 32 + include/asm-nios2nommu/pgtable.h | 104 + include/asm-nios2nommu/pio_struct.h | 14 + include/asm-nios2nommu/poll.h | 48 + include/asm-nios2nommu/posix_types.h | 89 + include/asm-nios2nommu/preem_latency.h | 39 + include/asm-nios2nommu/processor.h | 148 + include/asm-nios2nommu/ptrace.h | 141 + include/asm-nios2nommu/resource.h | 6 + include/asm-nios2nommu/rmap.h | 2 + include/asm-nios2nommu/scatterlist.h | 13 + include/asm-nios2nommu/sections.h | 30 + include/asm-nios2nommu/segment.h | 75 + include/asm-nios2nommu/semaphore-helper.h | 99 + include/asm-nios2nommu/semaphore.h | 152 + include/asm-nios2nommu/sembuf.h | 48 + include/asm-nios2nommu/setup.h | 31 + include/asm-nios2nommu/shmbuf.h | 64 + include/asm-nios2nommu/shmparam.h | 30 + include/asm-nios2nommu/sigcontext.h | 35 + include/asm-nios2nommu/siginfo.h | 28 + include/asm-nios2nommu/signal.h | 181 + include/asm-nios2nommu/smp.h | 32 + include/asm-nios2nommu/socket.h | 77 + include/asm-nios2nommu/sockios.h | 38 + include/asm-nios2nommu/spi.h | 92 + include/asm-nios2nommu/spi_struct.h | 57 + include/asm-nios2nommu/spinlock.h | 30 + include/asm-nios2nommu/stat.h | 102 + include/asm-nios2nommu/statfs.h | 30 + include/asm-nios2nommu/string.h | 45 + include/asm-nios2nommu/system.h | 171 + include/asm-nios2nommu/termbits.h | 199 + include/asm-nios2nommu/termios.h | 132 + include/asm-nios2nommu/thread_info.h | 127 + include/asm-nios2nommu/timer_struct.h | 38 + include/asm-nios2nommu/timex.h | 48 + include/asm-nios2nommu/tlb.h | 35 + include/asm-nios2nommu/tlbflush.h | 86 + include/asm-nios2nommu/topology.h | 30 + include/asm-nios2nommu/traps.h | 27 + include/asm-nios2nommu/types.h | 91 + include/asm-nios2nommu/uaccess.h | 183 + include/asm-nios2nommu/uart_struct.h | 83 + include/asm-nios2nommu/ucontext.h | 63 + include/asm-nios2nommu/unaligned.h | 6 + include/asm-nios2nommu/unistd.h | 694 ++ include/asm-nios2nommu/user.h | 112 + include/asm-nios2nommu/virtconvert.h | 46 + include/asm-sh/fast_timer.h | 104 + include/asm-sh/namei.h | 2 +- include/asm-sh/ptrace.h | 1 + include/asm-sh/sections.h | 2 +- include/asm-sh/snapgear.h | 7 +- include/asm-um/param.h | 4 + include/linux/blkdev.h | 4 + include/linux/compiler-gcc+.h | 16 + include/linux/compiler-gcc.h | 2 + include/linux/compiler-gcc2.h | 24 + include/linux/compiler-gcc3.h | 12 + include/linux/compiler.h | 2 + include/linux/config.h | 1 + include/linux/dm270-id.h | 106 + include/linux/elevator.h | 4 + include/linux/fast_timer.h | 8 + include/linux/fs.h | 4 + include/linux/i2c-id.h | 3 + include/linux/if_bridge.h | 1 + include/linux/if_ether.h | 1 + include/linux/kernel.h | 5 + include/linux/ledman.h | 109 + include/linux/miscdevice.h | 1 + include/linux/mm.h | 16 +- include/linux/mm_types.h | 8 + include/linux/mmc/mmc.h | 5 + include/linux/mtd/doc2000.h | 21 +- include/linux/mtd/plat-ram.h | 3 +- include/linux/netfilter_ipv4/ip_conntrack.h | 9 + include/linux/netfilter_ipv4/ip_conntrack_h323.h | 4 + .../ip_conntrack_helper_h323_types.h | 61 + include/linux/netfilter_ipv4/ipt_layer7.h | 26 + include/linux/netfilter_ipv4/ipt_time.h | 18 + include/linux/oom.h | 1 + include/linux/pci_ids.h | 4 + include/linux/ppp-comp.h | 7 + include/linux/serial.h | 1 + include/linux/serial_core.h | 20 + include/linux/serial_reg.h | 10 +- include/linux/squashfs_fs.h | 523 ++ include/linux/squashfs_fs_i.h | 43 + include/linux/squashfs_fs_sb.h | 65 + include/linux/string.h | 6 + include/linux/types.h | 2 + include/linux/usb_isp1362.h | 42 + include/net/xfrmudp.h | 10 + init/Kconfig | 2 +- init/do_mounts_rd.c | 17 +- init/main.c | 23 +- ipc/msg.c | 4 + kernel/compat.c | 1 + kernel/fork.c | 4 + kernel/printk.c | 5 + kernel/softirq.c | 23 +- kernel/time.c | 69 +- kernel/timer.c | 3 + linux.bin | Bin 0 -> 2005800 bytes mm/filemap.c | 52 + mm/nommu.c | 103 +- mm/oom_kill.c | 3 +- mm/page-writeback.c | 8 + mm/page_alloc.c | 82 + mm/slab.c | 28 +- mm/swapfile.c | 4 + mm/truncate.c | 20 + mm/vmscan.c | 42 + net/Kconfig | 1 + net/Makefile | 1 + net/bridge/br_netfilter.c | 16 +- net/bridge/br_stp_bpdu.c | 51 +- net/core/skbuff.c | 3 + net/ipsec/Makefile | 24 + net/ipsec/addrtoa.c | 1 + net/ipsec/addrtot.c | 1 + net/ipsec/addrtypeof.c | 1 + net/ipsec/adler32.c | 1 + net/ipsec/aes/Makefile | 15 + net/ipsec/anyaddr.c | 1 + net/ipsec/datatot.c | 1 + net/ipsec/deflate.c | 1 + net/ipsec/des/Makefile | 22 + net/ipsec/goodmask.c | 1 + net/ipsec/infblock.c | 1 + net/ipsec/infcodes.c | 1 + net/ipsec/inffast.c | 1 + net/ipsec/inflate.c | 1 + net/ipsec/inftrees.c | 1 + net/ipsec/infutil.c | 1 + net/ipsec/initaddr.c | 1 + net/ipsec/ipcomp.c | 1 + net/ipsec/ipsec_ah.c | 1 + net/ipsec/ipsec_alg.c | 1 + net/ipsec/ipsec_alg_cryptoapi.c | 1 + net/ipsec/ipsec_esp.c | 1 + net/ipsec/ipsec_init.c | 1 + net/ipsec/ipsec_ipcomp.c | 1 + net/ipsec/ipsec_ipip.c | 1 + net/ipsec/ipsec_kern24.c | 1 + net/ipsec/ipsec_life.c | 1 + net/ipsec/ipsec_mast.c | 1 + net/ipsec/ipsec_md5c.c | 1 + net/ipsec/ipsec_ocf.c | 1 + net/ipsec/ipsec_proc.c | 1 + net/ipsec/ipsec_radij.c | 1 + net/ipsec/ipsec_rcv.c | 1 + net/ipsec/ipsec_sa.c | 1 + net/ipsec/ipsec_sha1.c | 1 + net/ipsec/ipsec_snprintf.c | 1 + net/ipsec/ipsec_tunnel.c | 1 + net/ipsec/ipsec_xform.c | 1 + net/ipsec/ipsec_xmit.c | 1 + net/ipsec/match586.S | 1 + net/ipsec/match686.S | 1 + net/ipsec/pfkey_v2.c | 1 + net/ipsec/pfkey_v2_build.c | 1 + net/ipsec/pfkey_v2_debug.c | 1 + net/ipsec/pfkey_v2_ext_bits.c | 1 + net/ipsec/pfkey_v2_ext_process.c | 1 + net/ipsec/pfkey_v2_parse.c | 1 + net/ipsec/pfkey_v2_parser.c | 1 + net/ipsec/prng.c | 1 + net/ipsec/radij.c | 1 + net/ipsec/rangetoa.c | 1 + net/ipsec/satot.c | 1 + net/ipsec/subnetof.c | 1 + net/ipsec/subnettoa.c | 1 + net/ipsec/sysctl_net_ipsec.c | 1 + net/ipsec/trees.c | 1 + net/ipsec/ultoa.c | 1 + net/ipsec/ultot.c | 1 + net/ipsec/version.in.c | 1 + net/ipsec/zutil.c | 1 + net/ipv4/Kconfig | 6 + net/ipv4/af_inet.c | 12 + net/ipv4/ip_gre.c | 110 +- net/ipv4/netfilter/Kconfig | 39 + net/ipv4/netfilter/Makefile | 4 + net/ipv4/netfilter/ip_conntrack_core.c | 7 + net/ipv4/netfilter/ip_conntrack_ftp.c | 11 +- net/ipv4/netfilter/ip_conntrack_standalone.c | 6 + net/ipv4/netfilter/ip_nat_standalone.c | 8 +- net/ipv4/netfilter/ipt_TCPMSS.c | 18 +- net/ipv4/netfilter/ipt_layer7.c | 580 ++ net/ipv4/netfilter/ipt_time.c | 178 + net/ipv4/netfilter/regexp/regexp.c | 1197 ++++ net/ipv4/netfilter/regexp/regexp.h | 41 + net/ipv4/netfilter/regexp/regmagic.h | 5 + net/ipv4/netfilter/regexp/regsub.c | 95 + net/ipv4/udp.c | 67 +- net/llc/Kconfig | 2 +- net/netfilter/nfnetlink_log.c | 22 +- net/sunrpc/pmap_clnt.c | 5 + net/sunrpc/xprtsock.c | 4 + scripts/Makefile.modinst | 3 +- scripts/Makefile.modpost | 2 +- scripts/mod/sumversion.c | 1 + usr/Makefile | 4 +- 1025 files changed, 135846 insertions(+), 6570 deletions(-) create mode 100644 Makefile-bak-02162007 create mode 100644 arch/arm/boot/compressed/head-espd_4510b.S create mode 100644 arch/arm/boot/compressed/head-ks8695.S create mode 100644 arch/arm/boot/compressed/head-p2001.S create mode 100644 arch/arm/boot/compressed/head-s3c44b0.S create mode 100644 arch/arm/boot/compressed/head.S-bak-06072007 create mode 100644 arch/arm/configs/EM1220_defconfig create mode 100644 arch/arm/configs/EM1240_defconfig create mode 100644 arch/arm/configs/GDB_ARMulator_defconfig create mode 100644 arch/arm/configs/UC7110_defconfig create mode 100644 arch/arm/configs/UC7112_defconfig create mode 100644 arch/arm/configs/atmel_defconfig create mode 100644 arch/arm/configs/espd_4510b_defconfig create mode 100644 arch/arm/configs/ks8695_config create mode 100644 arch/arm/configs/lpc22xx_defconfig create mode 100644 arch/arm/configs/p2001_defconfig create mode 100644 arch/arm/configs/s3c24a0_mmu_defconfig create mode 100644 arch/arm/configs/s3c24a0_nommu_defconfig create mode 100644 arch/arm/configs/s3c3410_defconfig create mode 100644 arch/arm/configs/s3c44b0x_defconfig create mode 100644 arch/arm/configs/s5c7375_defconfig create mode 100644 arch/arm/kernel/initrd-mtd.c create mode 100644 arch/arm/mach-adifcc/Kconfig create mode 100644 arch/arm/mach-atmel/Kconfig create mode 100644 arch/arm/mach-atmel/Makefile create mode 100644 arch/arm/mach-atmel/Makefile.boot create mode 100644 arch/arm/mach-atmel/arch.c create mode 100644 arch/arm/mach-atmel/head.S create mode 100644 arch/arm/mach-atmel/irq.c create mode 100644 arch/arm/mach-atmel/time.c create mode 100644 arch/arm/mach-espd_4510b/Kconfig create mode 100644 arch/arm/mach-espd_4510b/Makefile create mode 100644 arch/arm/mach-espd_4510b/Makefile.boot create mode 100644 arch/arm/mach-espd_4510b/arch.c create mode 100644 arch/arm/mach-espd_4510b/dma.c create mode 100644 arch/arm/mach-espd_4510b/head.S create mode 100644 arch/arm/mach-espd_4510b/irq.c create mode 100644 arch/arm/mach-espd_4510b/mm.c create mode 100644 arch/arm/mach-espd_4510b/time.c create mode 100644 arch/arm/mach-ixp4xx/ess710-pci.c create mode 100644 arch/arm/mach-ixp4xx/sg-setup.c create mode 100644 arch/arm/mach-ixp4xx/sg5xx-pci.c create mode 100644 arch/arm/mach-ixp4xx/sg720-pci.c create mode 100644 arch/arm/mach-ks8695/Kconfig create mode 100644 arch/arm/mach-ks8695/Makefile create mode 100644 arch/arm/mach-ks8695/Makefile.boot create mode 100644 arch/arm/mach-ks8695/arch.c create mode 100644 arch/arm/mach-ks8695/irq.c create mode 100644 arch/arm/mach-ks8695/mm.c create mode 100644 arch/arm/mach-ks8695/pci.c create mode 100644 arch/arm/mach-ks8695/time.c create mode 100644 arch/arm/mach-lpc22xx/Kconfig create mode 100644 arch/arm/mach-lpc22xx/Makefile create mode 100644 arch/arm/mach-lpc22xx/arch.c create mode 100644 arch/arm/mach-lpc22xx/head.S create mode 100644 arch/arm/mach-lpc22xx/irq.c create mode 100644 arch/arm/mach-lpc22xx/time.c create mode 100644 arch/arm/mach-moxart/Kconfig create mode 100644 arch/arm/mach-moxart/Makefile create mode 100644 arch/arm/mach-moxart/ahb_dma.c create mode 100644 arch/arm/mach-moxart/apb_dma.c create mode 100644 arch/arm/mach-moxart/arch.c create mode 100644 arch/arm/mach-moxart/cpe_dma.c create mode 100644 arch/arm/mach-moxart/debug.c create mode 100644 arch/arm/mach-moxart/debug_cpe.c create mode 100644 arch/arm/mach-moxart/dma.h create mode 100644 arch/arm/mach-moxart/entry-macro.S create mode 100644 arch/arm/mach-moxart/ftpci.c create mode 100644 arch/arm/mach-moxart/gpio.c create mode 100644 arch/arm/mach-moxart/head.S create mode 100644 arch/arm/mach-moxart/irq.c create mode 100644 arch/arm/mach-moxart/irq.c-bak-07312007 create mode 100644 arch/arm/mach-moxart/pci.c create mode 100644 arch/arm/mach-moxart/timer.c create mode 100644 arch/arm/mach-p2001/Kconfig create mode 100644 arch/arm/mach-p2001/Makefile create mode 100644 arch/arm/mach-p2001/Makefile.boot create mode 100644 arch/arm/mach-p2001/arch.c create mode 100644 arch/arm/mach-p2001/entry-macro.S create mode 100644 arch/arm/mach-p2001/head.S create mode 100644 arch/arm/mach-p2001/irq.c create mode 100644 arch/arm/mach-p2001/p2001_cpufreq.c create mode 100644 arch/arm/mach-p2001/time.c create mode 100644 arch/arm/mach-s3c24a0/Kconfig create mode 100644 arch/arm/mach-s3c24a0/Makefile create mode 100644 arch/arm/mach-s3c24a0/Makefile.boot create mode 100644 arch/arm/mach-s3c24a0/clocks.c create mode 100644 arch/arm/mach-s3c24a0/generic.c create mode 100644 arch/arm/mach-s3c24a0/generic.h create mode 100644 arch/arm/mach-s3c24a0/head.S create mode 100644 arch/arm/mach-s3c24a0/irq.c create mode 100644 arch/arm/mach-s3c24a0/leds-smdk.c create mode 100644 arch/arm/mach-s3c24a0/leds.c create mode 100644 arch/arm/mach-s3c24a0/leds.h create mode 100644 arch/arm/mach-s3c24a0/registers.c create mode 100644 arch/arm/mach-s3c24a0/smdk.c create mode 100644 arch/arm/mach-s3c24a0/time.c create mode 100644 arch/arm/mach-s3c3410/Kconfig create mode 100644 arch/arm/mach-s3c3410/Makefile create mode 100644 arch/arm/mach-s3c3410/arch.c create mode 100644 arch/arm/mach-s3c3410/dma.c create mode 100644 arch/arm/mach-s3c3410/head.S create mode 100644 arch/arm/mach-s3c3410/irq.c create mode 100644 arch/arm/mach-s3c3410/mm.c create mode 100644 arch/arm/mach-s3c3410/time.c create mode 100644 arch/arm/mach-s3c44b0x/Kconfig create mode 100644 arch/arm/mach-s3c44b0x/Makefile create mode 100644 arch/arm/mach-s3c44b0x/Makefile.boot create mode 100644 arch/arm/mach-s3c44b0x/arch.c create mode 100644 arch/arm/mach-s3c44b0x/cache.S create mode 100644 arch/arm/mach-s3c44b0x/dma.c create mode 100644 arch/arm/mach-s3c44b0x/driver/Kconfig create mode 100644 arch/arm/mach-s3c44b0x/driver/Makefile create mode 100644 arch/arm/mach-s3c44b0x/driver/console.c create mode 100644 arch/arm/mach-s3c44b0x/driver/led.c create mode 100644 arch/arm/mach-s3c44b0x/driver/rtl8019.c create mode 100644 arch/arm/mach-s3c44b0x/driver/rtl8019.h create mode 100644 arch/arm/mach-s3c44b0x/head.S create mode 100644 arch/arm/mach-s3c44b0x/irq.c create mode 100644 arch/arm/mach-s3c44b0x/mm.c create mode 100644 arch/arm/mach-s3c44b0x/time.c create mode 100644 arch/arm/mach-s5c7375/Kconfig create mode 100644 arch/arm/mach-s5c7375/Makefile create mode 100644 arch/arm/mach-s5c7375/Makefile.boot create mode 100644 arch/arm/mach-s5c7375/arch.c create mode 100644 arch/arm/mach-s5c7375/dma.c create mode 100644 arch/arm/mach-s5c7375/head.S create mode 100644 arch/arm/mach-s5c7375/irq.c create mode 100644 arch/arm/mach-s5c7375/time.c create mode 100644 arch/arm/mm/Kconfig-bak-03032007 create mode 100644 arch/arm/mm/abort-ev0.S create mode 100644 arch/arm/mm/abort-ev0t.S create mode 100644 arch/arm/mm/cache-v0.S create mode 100644 arch/arm/mm/consistent-nommu.c rewrite arch/arm/mm/proc-arm940.S (80%) rewrite arch/arm/mm/proc-arm946.S (81%) create mode 100644 arch/arm/mm/proc-lpc22xx.S create mode 100644 arch/arm/mm/proc-s3c4510b.S create mode 100644 arch/m68knommu/platform/532x/spi-mcf532x.c create mode 100644 arch/m68knommu/platform/532x/usb-mcf532x.c create mode 100644 arch/m68knommu/platform/68VZ328/screen.xbm create mode 100644 arch/m68knommu/platform/68VZ328/xbm2lcd.pl create mode 100644 arch/nios2nommu/ChangeLog create mode 100644 arch/nios2nommu/Kconfig create mode 100644 arch/nios2nommu/Kconfig.debug create mode 100644 arch/nios2nommu/Makefile create mode 100644 arch/nios2nommu/boot/Makefile create mode 100644 arch/nios2nommu/boot/compressed/Makefile create mode 100644 arch/nios2nommu/boot/compressed/head.S create mode 100644 arch/nios2nommu/boot/compressed/install.sh create mode 100644 arch/nios2nommu/boot/compressed/misc.c create mode 100644 arch/nios2nommu/boot/compressed/nios2_sio.c create mode 100644 arch/nios2nommu/defconfig create mode 100644 arch/nios2nommu/drivers/Kconfig create mode 100644 arch/nios2nommu/drivers/Makefile create mode 100644 arch/nios2nommu/drivers/altfb.c create mode 100644 arch/nios2nommu/drivers/altps2.c create mode 100644 arch/nios2nommu/drivers/i2c-gpio.c create mode 100644 arch/nios2nommu/drivers/pci/Kconfig create mode 100644 arch/nios2nommu/drivers/pci/Makefile create mode 100644 arch/nios2nommu/drivers/pci/altpci.c create mode 100644 arch/nios2nommu/drivers/pci/pci-auto.c create mode 100644 arch/nios2nommu/drivers/pci/pci.c create mode 100644 arch/nios2nommu/drivers/pci/setup-irq.c create mode 100644 arch/nios2nommu/kernel/ChangeLog create mode 100644 arch/nios2nommu/kernel/Makefile create mode 100644 arch/nios2nommu/kernel/asm-offsets.c create mode 100644 arch/nios2nommu/kernel/dma.c create mode 100644 arch/nios2nommu/kernel/entry.S create mode 100644 arch/nios2nommu/kernel/head.S create mode 100644 arch/nios2nommu/kernel/init_task.c create mode 100644 arch/nios2nommu/kernel/io.c create mode 100644 arch/nios2nommu/kernel/irq.c create mode 100644 arch/nios2nommu/kernel/module.c create mode 100644 arch/nios2nommu/kernel/nios2_ksyms.c create mode 100644 arch/nios2nommu/kernel/nios_gdb_stub.c create mode 100644 arch/nios2nommu/kernel/nios_gdb_stub.h create mode 100644 arch/nios2nommu/kernel/nios_gdb_stub_io.c create mode 100644 arch/nios2nommu/kernel/nios_gdb_stub_isr.S create mode 100644 arch/nios2nommu/kernel/pio.c create mode 100644 arch/nios2nommu/kernel/process.c create mode 100644 arch/nios2nommu/kernel/ptrace.c create mode 100644 arch/nios2nommu/kernel/semaphore.c create mode 100644 arch/nios2nommu/kernel/setup.c create mode 100644 arch/nios2nommu/kernel/signal.c create mode 100644 arch/nios2nommu/kernel/start.c create mode 100644 arch/nios2nommu/kernel/sys_nios2.c create mode 100644 arch/nios2nommu/kernel/syscalltable.S create mode 100644 arch/nios2nommu/kernel/time.c create mode 100644 arch/nios2nommu/kernel/traps.c create mode 100644 arch/nios2nommu/kernel/usb.c create mode 100644 arch/nios2nommu/lib/Makefile create mode 100644 arch/nios2nommu/lib/checksum.c create mode 100644 arch/nios2nommu/lib/memcpy.c create mode 100644 arch/nios2nommu/lib/string.c create mode 100644 arch/nios2nommu/mm/Makefile create mode 100644 arch/nios2nommu/mm/dma-noncoherent.c create mode 100644 arch/nios2nommu/mm/extable.c create mode 100644 arch/nios2nommu/mm/init.c create mode 100644 arch/nios2nommu/mm/ioremap.c create mode 100644 arch/nios2nommu/mm/memory.c create mode 100644 arch/nios2nommu/scripts/PTF/PTFParser.pm create mode 100644 arch/nios2nommu/scripts/PTF/PTFParser.yp create mode 100644 arch/nios2nommu/scripts/PTF/PTFSection.pm create mode 100644 arch/nios2nommu/scripts/PTF/SystemPTF.pm create mode 100644 arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm create mode 100644 arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm create mode 100644 arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm create mode 100644 arch/nios2nommu/scripts/gen_nios2_system.h.pl create mode 100644 arch/nios2nommu/scripts/hwselect.pl create mode 100644 arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm create mode 100644 arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm create mode 120000 arch/um/Kconfig.arch create mode 100644 drivers/char/altera_pio_button.c create mode 100644 drivers/char/fast_timer.c create mode 100644 drivers/char/gpio.c create mode 100644 drivers/char/gpio.c-bak-07312007 create mode 100644 drivers/char/keypad.c create mode 100644 drivers/char/lcd_16207.c create mode 100644 drivers/char/lcm0.c create mode 100644 drivers/char/lcm1.c create mode 100644 drivers/char/lcm2.c create mode 100644 drivers/char/lcm3.c create mode 100644 drivers/char/ledman.c create mode 100644 drivers/char/m41t11m6.c create mode 100644 drivers/char/mcf_qspi.c create mode 100644 drivers/char/mcf_qspi.h create mode 100644 drivers/char/mcfwatchdog.c create mode 100644 drivers/char/moxalcm.h rewrite drivers/char/mxser.c (80%) create mode 100644 drivers/char/resetswitch.c create mode 100644 drivers/char/resetswitch.c-bak-07312007 create mode 100644 drivers/char/resetswitch.c-old rewrite drivers/char/rtc.c (91%) create mode 100644 drivers/char/rtc.c-bak-09052007 create mode 100644 drivers/char/rtc.c-old create mode 100644 drivers/char/snapdog.c create mode 100644 drivers/char/watchdog/avalonwdt.c create mode 100644 drivers/char/watchdog/m5272_wdt.c create mode 100644 drivers/char/watchdog/uc7110wdt.c create mode 100644 drivers/i2c/busses/i2c-mcf.c create mode 100644 drivers/i2c/busses/i2c-mcf.h create mode 100644 drivers/i2c/chips/m41t11.c create mode 100644 drivers/ide/arm/adi-coyote.c create mode 100644 drivers/ide/pci/p20575.c create mode 100644 drivers/mmc/moxasd.c create mode 100644 drivers/mmc/moxasd.c-bak-07122007 create mode 100644 drivers/mmc/moxasd.h create mode 100644 drivers/mtd/chips/epcs.c create mode 100644 drivers/mtd/chips/epcs.h create mode 100644 drivers/mtd/chips/epcs_low.c create mode 100644 drivers/mtd/maps/altera.c create mode 100644 drivers/mtd/maps/avnet5282.c create mode 100644 drivers/mtd/maps/cobra5272.c create mode 100644 drivers/mtd/maps/cobra5282.c create mode 100644 drivers/mtd/maps/cobra5329.c create mode 100644 drivers/mtd/maps/dm270-flash.c create mode 100644 drivers/mtd/maps/em1110.c create mode 100644 drivers/mtd/maps/em1220.c create mode 100644 drivers/mtd/maps/em1220_dlin.c create mode 100644 drivers/mtd/maps/em1240.c create mode 100644 drivers/mtd/maps/em1240_ivtc.c create mode 100644 drivers/mtd/maps/em1240_mt.c create mode 100644 drivers/mtd/maps/epcs_map.c create mode 100644 drivers/mtd/maps/m520x.c create mode 100644 drivers/mtd/maps/microtronix.c create mode 100644 drivers/mtd/maps/snaparm.c create mode 100644 drivers/mtd/maps/snapgear-uc.c create mode 100644 drivers/mtd/maps/snapgeode.c create mode 100644 drivers/mtd/maps/uc7101.c create mode 100644 drivers/mtd/maps/uc7110.c create mode 100644 drivers/mtd/maps/uc7112.c create mode 100644 drivers/mtd/maps/w311_test.c create mode 100644 drivers/mtd/maps/w315_ec.c create mode 100644 drivers/mtd/maps/w321_gl2.c create mode 100644 drivers/mtd/nand/m5329.c create mode 100644 drivers/net/arm/eth_moxa.c create mode 100644 drivers/net/arm/eth_moxa.h create mode 100644 drivers/net/arm/eth_s3c4510b.c create mode 100644 drivers/net/arm/eth_s3c4510b.h create mode 100644 drivers/net/arm/p2001_eth.c create mode 100644 drivers/net/cs89x0_defs.h create mode 100644 drivers/net/cs89x0_fct.h create mode 100644 drivers/net/ks8695/Makefile create mode 100644 drivers/net/ks8695/ks8695_cache.c create mode 100644 drivers/net/ks8695/ks8695_cache.h create mode 100644 drivers/net/ks8695/ks8695_chipdef.h create mode 100644 drivers/net/ks8695/ks8695_drv.h create mode 100644 drivers/net/ks8695/ks8695_fxhw.c create mode 100644 drivers/net/ks8695/ks8695_fxhw.h create mode 100644 drivers/net/ks8695/ks8695_ioctrl.h create mode 100644 drivers/net/ks8695/ks8695_kcompat.h create mode 100644 drivers/net/ks8695/ks8695_main.c create mode 100644 drivers/net/mtip1000.c create mode 100644 drivers/net/mtip1000.h create mode 100644 drivers/net/ns83865phy.h create mode 100644 drivers/net/open_eth.c create mode 100644 drivers/net/open_eth.h create mode 100644 drivers/net/stdphy.h create mode 100644 drivers/net/tdk78phy.h create mode 100644 drivers/rtc/rtc-ds1302.c create mode 100644 drivers/serial/NIOSserial.c create mode 100644 drivers/serial/NIOSserial.h create mode 100644 drivers/serial/altera_juart.c create mode 100644 drivers/serial/dcc.c create mode 100644 drivers/serial/mcf.c create mode 100644 drivers/serial/p2001_uart.c create mode 100644 drivers/serial/serial_atmel.c create mode 100644 drivers/serial/serial_atmel.h create mode 100644 drivers/serial/serial_dm270.c create mode 100644 drivers/serial/serial_ks8695.c create mode 100644 drivers/serial/serial_s3c24a0.c create mode 100644 drivers/serial/serial_s3c4510b.c create mode 100644 drivers/spi/DS1305RTC.c create mode 100644 drivers/spi/mcf_qspi.c create mode 100644 drivers/usb/host/ehci-moxaart.c create mode 100644 drivers/video/dm270fb.c create mode 100644 drivers/video/dm270fb.h create mode 100644 drivers/video/m532xfb.c create mode 100644 fs/squashfs/LzmaDecode.c create mode 100644 fs/squashfs/LzmaDecode.h create mode 100644 fs/squashfs/LzmaWrapper.c create mode 100644 fs/squashfs/LzmaWrapper.h create mode 100644 fs/squashfs/Makefile create mode 100644 fs/squashfs/inode.c create mode 100644 include/asm-arm/arch-atmel/at91x40.h create mode 100644 include/asm-arm/arch-atmel/at91x63.h create mode 100644 include/asm-arm/arch-atmel/dma.h create mode 100644 include/asm-arm/arch-atmel/entry-macro.S create mode 100644 include/asm-arm/arch-atmel/hardware.h create mode 100644 include/asm-arm/arch-atmel/io.h create mode 100644 include/asm-arm/arch-atmel/irq.h create mode 100644 include/asm-arm/arch-atmel/irqs.h create mode 100644 include/asm-arm/arch-atmel/memory.h create mode 100644 include/asm-arm/arch-atmel/param.h create mode 100644 include/asm-arm/arch-atmel/system.h create mode 100644 include/asm-arm/arch-atmel/time.h create mode 100644 include/asm-arm/arch-atmel/timex.h create mode 100644 include/asm-arm/arch-atmel/uncompress.h create mode 100644 include/asm-arm/arch-atmel/vmalloc.h create mode 100644 include/asm-arm/arch-espd_4510b/dma.h create mode 100644 include/asm-arm/arch-espd_4510b/entry-macro.S create mode 100644 include/asm-arm/arch-espd_4510b/hardware.h create mode 100644 include/asm-arm/arch-espd_4510b/io.h create mode 100644 include/asm-arm/arch-espd_4510b/irq.h create mode 100644 include/asm-arm/arch-espd_4510b/irqs.h create mode 100644 include/asm-arm/arch-espd_4510b/keyboard.h create mode 100644 include/asm-arm/arch-espd_4510b/memory.h create mode 100644 include/asm-arm/arch-espd_4510b/param.h create mode 100644 include/asm-arm/arch-espd_4510b/s3c4510b.h create mode 100644 include/asm-arm/arch-espd_4510b/system.h create mode 100644 include/asm-arm/arch-espd_4510b/time.h create mode 100644 include/asm-arm/arch-espd_4510b/timex.h create mode 100644 include/asm-arm/arch-espd_4510b/uart.h create mode 100644 include/asm-arm/arch-espd_4510b/uncompress.c create mode 100644 include/asm-arm/arch-espd_4510b/uncompress.h create mode 100644 include/asm-arm/arch-espd_4510b/vmalloc.h create mode 100644 include/asm-arm/arch-ixp4xx/fast_timer.h create mode 100644 include/asm-arm/arch-ixp4xx/ide.h create mode 100644 include/asm-arm/arch-ixp4xx/sg.h create mode 100644 include/asm-arm/arch-ks8695/debug-macro.S create mode 100644 include/asm-arm/arch-ks8695/dma.h create mode 100644 include/asm-arm/arch-ks8695/entry-macro.S create mode 100644 include/asm-arm/arch-ks8695/fast_timer.h create mode 100644 include/asm-arm/arch-ks8695/hardware.h create mode 100644 include/asm-arm/arch-ks8695/io.h create mode 100644 include/asm-arm/arch-ks8695/irqs.h create mode 100644 include/asm-arm/arch-ks8695/ks8695-pci.h create mode 100644 include/asm-arm/arch-ks8695/ks8695-regs.h create mode 100644 include/asm-arm/arch-ks8695/memory.h create mode 100644 include/asm-arm/arch-ks8695/param.h create mode 100644 include/asm-arm/arch-ks8695/system.h create mode 100644 include/asm-arm/arch-ks8695/timex.h create mode 100644 include/asm-arm/arch-ks8695/uncompress.h create mode 100644 include/asm-arm/arch-ks8695/vmalloc.h create mode 100644 include/asm-arm/arch-lpc22xx/dma.h create mode 100644 include/asm-arm/arch-lpc22xx/entry-macro.S create mode 100644 include/asm-arm/arch-lpc22xx/hardware.h create mode 100644 include/asm-arm/arch-lpc22xx/io.h create mode 100644 include/asm-arm/arch-lpc22xx/irq.h create mode 100644 include/asm-arm/arch-lpc22xx/irqs.h create mode 100644 include/asm-arm/arch-lpc22xx/keyboard.h create mode 100644 include/asm-arm/arch-lpc22xx/log create mode 100644 include/asm-arm/arch-lpc22xx/lpc22xx.h create mode 100644 include/asm-arm/arch-lpc22xx/memory.h create mode 100644 include/asm-arm/arch-lpc22xx/param.h create mode 100644 include/asm-arm/arch-lpc22xx/serial.h create mode 100644 include/asm-arm/arch-lpc22xx/system.h create mode 100644 include/asm-arm/arch-lpc22xx/time.h create mode 100644 include/asm-arm/arch-lpc22xx/timex.h create mode 100644 include/asm-arm/arch-lpc22xx/vmalloc.h create mode 100644 include/asm-arm/arch-moxart/cpe_int.h create mode 100644 include/asm-arm/arch-moxart/cpe_time.h create mode 100644 include/asm-arm/arch-moxart/dma.h create mode 100644 include/asm-arm/arch-moxart/entry-macro.S create mode 100644 include/asm-arm/arch-moxart/ftpci.h create mode 100644 include/asm-arm/arch-moxart/gpio.h create mode 100644 include/asm-arm/arch-moxart/hardware.h create mode 100644 include/asm-arm/arch-moxart/io.h create mode 100644 include/asm-arm/arch-moxart/irq.h create mode 100644 include/asm-arm/arch-moxart/irq.h-bak-11212005 create mode 100644 include/asm-arm/arch-moxart/irqs.h create mode 100644 include/asm-arm/arch-moxart/memory.h create mode 100644 include/asm-arm/arch-moxart/moxa-uart.h create mode 100644 include/asm-arm/arch-moxart/moxa.h create mode 100644 include/asm-arm/arch-moxart/param.h create mode 100644 include/asm-arm/arch-moxart/processor.h create mode 100644 include/asm-arm/arch-moxart/serial.h create mode 100644 include/asm-arm/arch-moxart/system.h create mode 100644 include/asm-arm/arch-moxart/time.h create mode 100644 include/asm-arm/arch-moxart/timex.h create mode 100644 include/asm-arm/arch-moxart/uncompress.h create mode 100644 include/asm-arm/arch-p2001/debug-macro.S create mode 100644 include/asm-arm/arch-p2001/dma.h create mode 100644 include/asm-arm/arch-p2001/entry-macro.S create mode 100644 include/asm-arm/arch-p2001/hardware.h create mode 100644 include/asm-arm/arch-p2001/io.h create mode 100644 include/asm-arm/arch-p2001/irq.h create mode 100644 include/asm-arm/arch-p2001/irqs.h create mode 100644 include/asm-arm/arch-p2001/memory.h create mode 100644 include/asm-arm/arch-p2001/param.h create mode 100644 include/asm-arm/arch-p2001/system.h create mode 100644 include/asm-arm/arch-p2001/timex.h create mode 100644 include/asm-arm/arch-p2001/uncompress.h create mode 100644 include/asm-arm/arch-p2001/vmalloc.h create mode 100644 include/asm-arm/arch-s3c24a0/S3C24A0.h create mode 100644 include/asm-arm/arch-s3c24a0/bitfield.h create mode 100644 include/asm-arm/arch-s3c24a0/clocks.h create mode 100644 include/asm-arm/arch-s3c24a0/debug-macro.S create mode 100644 include/asm-arm/arch-s3c24a0/dma.h create mode 100644 include/asm-arm/arch-s3c24a0/entry-macro.S create mode 100644 include/asm-arm/arch-s3c24a0/hardware.h create mode 100644 include/asm-arm/arch-s3c24a0/ide.h create mode 100644 include/asm-arm/arch-s3c24a0/io.h create mode 100644 include/asm-arm/arch-s3c24a0/irq.h create mode 100644 include/asm-arm/arch-s3c24a0/irqs.h create mode 100644 include/asm-arm/arch-s3c24a0/keyboard.h create mode 100644 include/asm-arm/arch-s3c24a0/memory.h create mode 100644 include/asm-arm/arch-s3c24a0/param.h create mode 100644 include/asm-arm/arch-s3c24a0/s3c24a0-common.h create mode 100644 include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h create mode 100644 include/asm-arm/arch-s3c24a0/s3c24a0-key.h create mode 100644 include/asm-arm/arch-s3c24a0/s3c24a0-machine.h create mode 100644 include/asm-arm/arch-s3c24a0/s3c24a0_nand.h create mode 100644 include/asm-arm/arch-s3c24a0/smdk.h create mode 100644 include/asm-arm/arch-s3c24a0/system.h create mode 100644 include/asm-arm/arch-s3c24a0/time.h create mode 100644 include/asm-arm/arch-s3c24a0/timex.h create mode 100644 include/asm-arm/arch-s3c24a0/uncompress-jtag.h create mode 100644 include/asm-arm/arch-s3c24a0/uncompress.h create mode 100644 include/asm-arm/arch-s3c24a0/vmalloc.h create mode 100644 include/asm-arm/arch-s3c3410/dma.h create mode 100644 include/asm-arm/arch-s3c3410/entry-macro.S create mode 100644 include/asm-arm/arch-s3c3410/hardware.h create mode 100644 include/asm-arm/arch-s3c3410/io.h create mode 100644 include/asm-arm/arch-s3c3410/irq.h create mode 100644 include/asm-arm/arch-s3c3410/irqs.h create mode 100644 include/asm-arm/arch-s3c3410/keyboard.h create mode 100644 include/asm-arm/arch-s3c3410/memory.h create mode 100644 include/asm-arm/arch-s3c3410/param.h create mode 100644 include/asm-arm/arch-s3c3410/s3c3410.h create mode 100644 include/asm-arm/arch-s3c3410/system.h create mode 100644 include/asm-arm/arch-s3c3410/time.h create mode 100644 include/asm-arm/arch-s3c3410/timex.h create mode 100644 include/asm-arm/arch-s3c3410/vmalloc.h create mode 100644 include/asm-arm/arch-s3c44b0x/dma.h create mode 100644 include/asm-arm/arch-s3c44b0x/entry-macro.S create mode 100644 include/asm-arm/arch-s3c44b0x/hardware.h create mode 100644 include/asm-arm/arch-s3c44b0x/io.h create mode 100644 include/asm-arm/arch-s3c44b0x/irq.h create mode 100644 include/asm-arm/arch-s3c44b0x/irqs.h create mode 100644 include/asm-arm/arch-s3c44b0x/keyboard.h create mode 100644 include/asm-arm/arch-s3c44b0x/memory.h create mode 100644 include/asm-arm/arch-s3c44b0x/param.h create mode 100644 include/asm-arm/arch-s3c44b0x/s3c44b0x.h create mode 100644 include/asm-arm/arch-s3c44b0x/system.h create mode 100644 include/asm-arm/arch-s3c44b0x/time.h create mode 100644 include/asm-arm/arch-s3c44b0x/timex.h create mode 100644 include/asm-arm/arch-s3c44b0x/uncompress.c create mode 100644 include/asm-arm/arch-s3c44b0x/uncompress.h create mode 100644 include/asm-arm/arch-s3c44b0x/vmalloc.h create mode 100644 include/asm-arm/arch-s5c7375/blkmem.h create mode 100644 include/asm-arm/arch-s5c7375/dma.h create mode 100644 include/asm-arm/arch-s5c7375/entry-macro.S create mode 100644 include/asm-arm/arch-s5c7375/hardware.h create mode 100644 include/asm-arm/arch-s5c7375/io.h create mode 100644 include/asm-arm/arch-s5c7375/irq.h create mode 100644 include/asm-arm/arch-s5c7375/irqs.h create mode 100644 include/asm-arm/arch-s5c7375/memory.h create mode 100644 include/asm-arm/arch-s5c7375/param.h create mode 100644 include/asm-arm/arch-s5c7375/s5c7375.h create mode 100644 include/asm-arm/arch-s5c7375/system.h create mode 100644 include/asm-arm/arch-s5c7375/time.h create mode 100644 include/asm-arm/arch-s5c7375/timex.h create mode 100644 include/asm-arm/arch-s5c7375/uncompress.h create mode 100644 include/asm-arm/arch-s5c7375/vmalloc.h create mode 100644 include/asm-arm/fast_timer.h create mode 100644 include/asm-arm/hardware/dcc.h create mode 100644 include/asm-arm/mach/i2c-gpio.h create mode 100644 include/asm-arm/nommu.h create mode 100644 include/asm-arm/nommu_context.h create mode 100644 include/asm-arm/uaccess-nommu.h create mode 100644 include/asm-i386/edd.h create mode 100644 include/asm-m68knommu/DS1305RTC.h create mode 100644 include/asm-m68knommu/cs89x0_fct.h create mode 100644 include/asm-m68knommu/mcfqspi.h create mode 100644 include/asm-m68knommu/rtc.h create mode 100644 include/asm-nios2nommu/ChangeLog create mode 100644 include/asm-nios2nommu/a.out.h create mode 100644 include/asm-nios2nommu/altera_juart.h create mode 100644 include/asm-nios2nommu/asm-macros.h create mode 100644 include/asm-nios2nommu/atomic.h create mode 100644 include/asm-nios2nommu/auxvec.h create mode 100644 include/asm-nios2nommu/bitops.h create mode 100644 include/asm-nios2nommu/bootinfo.h create mode 100644 include/asm-nios2nommu/bug.h create mode 100644 include/asm-nios2nommu/bugs.h create mode 100644 include/asm-nios2nommu/byteorder.h create mode 100644 include/asm-nios2nommu/cache.h create mode 100644 include/asm-nios2nommu/cachectl.h create mode 100644 include/asm-nios2nommu/cacheflush.h create mode 100644 include/asm-nios2nommu/checksum.h create mode 100644 include/asm-nios2nommu/cprefix.h create mode 100644 include/asm-nios2nommu/cpumask.h create mode 100644 include/asm-nios2nommu/cputime.h create mode 100644 include/asm-nios2nommu/current.h create mode 100644 include/asm-nios2nommu/delay.h create mode 100644 include/asm-nios2nommu/div64.h create mode 100644 include/asm-nios2nommu/dma-mapping.h create mode 100644 include/asm-nios2nommu/dma.h create mode 100644 include/asm-nios2nommu/elf.h create mode 100644 include/asm-nios2nommu/emergency-restart.h create mode 100644 include/asm-nios2nommu/entry.h create mode 100644 include/asm-nios2nommu/errno.h create mode 100644 include/asm-nios2nommu/fcntl.h create mode 100644 include/asm-nios2nommu/flat.h create mode 100644 include/asm-nios2nommu/futex.h create mode 100644 include/asm-nios2nommu/gpio.h create mode 100644 include/asm-nios2nommu/hardirq.h create mode 100644 include/asm-nios2nommu/hdreg.h create mode 100644 include/asm-nios2nommu/hw_irq.h create mode 100644 include/asm-nios2nommu/ide.h create mode 100644 include/asm-nios2nommu/init.h create mode 100644 include/asm-nios2nommu/io.h create mode 100644 include/asm-nios2nommu/ioctl.h create mode 100644 include/asm-nios2nommu/ioctls.h create mode 100644 include/asm-nios2nommu/ipc.h create mode 100644 include/asm-nios2nommu/ipcbuf.h create mode 100644 include/asm-nios2nommu/irq.h create mode 100644 include/asm-nios2nommu/irq_node.h create mode 100644 include/asm-nios2nommu/irq_regs.h create mode 100644 include/asm-nios2nommu/kmap_types.h create mode 100644 include/asm-nios2nommu/linkage.h create mode 100644 include/asm-nios2nommu/linux_logo.h create mode 100644 include/asm-nios2nommu/local.h create mode 100644 include/asm-nios2nommu/mc146818rtc.h create mode 100644 include/asm-nios2nommu/mman.h create mode 100644 include/asm-nios2nommu/mmu.h create mode 100644 include/asm-nios2nommu/mmu_context.h create mode 100644 include/asm-nios2nommu/module.h create mode 100644 include/asm-nios2nommu/msgbuf.h create mode 100644 include/asm-nios2nommu/mutex.h create mode 100644 include/asm-nios2nommu/namei.h create mode 100644 include/asm-nios2nommu/ndma.h create mode 100644 include/asm-nios2nommu/nios.h create mode 100644 include/asm-nios2nommu/page.h create mode 100644 include/asm-nios2nommu/param.h create mode 100644 include/asm-nios2nommu/pci.h create mode 100644 include/asm-nios2nommu/percpu.h create mode 100644 include/asm-nios2nommu/pgalloc.h create mode 100644 include/asm-nios2nommu/pgtable.h create mode 100644 include/asm-nios2nommu/pio_struct.h create mode 100644 include/asm-nios2nommu/poll.h create mode 100644 include/asm-nios2nommu/posix_types.h create mode 100644 include/asm-nios2nommu/preem_latency.h create mode 100644 include/asm-nios2nommu/processor.h create mode 100644 include/asm-nios2nommu/ptrace.h create mode 100644 include/asm-nios2nommu/resource.h create mode 100644 include/asm-nios2nommu/rmap.h create mode 100644 include/asm-nios2nommu/scatterlist.h create mode 100644 include/asm-nios2nommu/sections.h create mode 100644 include/asm-nios2nommu/segment.h create mode 100644 include/asm-nios2nommu/semaphore-helper.h create mode 100644 include/asm-nios2nommu/semaphore.h create mode 100644 include/asm-nios2nommu/sembuf.h create mode 100644 include/asm-nios2nommu/setup.h create mode 100644 include/asm-nios2nommu/shmbuf.h create mode 100644 include/asm-nios2nommu/shmparam.h create mode 100644 include/asm-nios2nommu/sigcontext.h create mode 100644 include/asm-nios2nommu/siginfo.h create mode 100644 include/asm-nios2nommu/signal.h create mode 100644 include/asm-nios2nommu/smp.h create mode 100644 include/asm-nios2nommu/socket.h create mode 100644 include/asm-nios2nommu/sockios.h create mode 100644 include/asm-nios2nommu/spi.h create mode 100644 include/asm-nios2nommu/spi_struct.h create mode 100644 include/asm-nios2nommu/spinlock.h create mode 100644 include/asm-nios2nommu/stat.h create mode 100644 include/asm-nios2nommu/statfs.h create mode 100644 include/asm-nios2nommu/string.h create mode 100644 include/asm-nios2nommu/system.h create mode 100644 include/asm-nios2nommu/termbits.h create mode 100644 include/asm-nios2nommu/termios.h create mode 100644 include/asm-nios2nommu/thread_info.h create mode 100644 include/asm-nios2nommu/timer_struct.h create mode 100644 include/asm-nios2nommu/timex.h create mode 100644 include/asm-nios2nommu/tlb.h create mode 100644 include/asm-nios2nommu/tlbflush.h create mode 100644 include/asm-nios2nommu/topology.h create mode 100644 include/asm-nios2nommu/traps.h create mode 100644 include/asm-nios2nommu/types.h create mode 100644 include/asm-nios2nommu/uaccess.h create mode 100644 include/asm-nios2nommu/uart_struct.h create mode 100644 include/asm-nios2nommu/ucontext.h create mode 100644 include/asm-nios2nommu/unaligned.h create mode 100644 include/asm-nios2nommu/unistd.h create mode 100644 include/asm-nios2nommu/user.h create mode 100644 include/asm-nios2nommu/virtconvert.h create mode 100644 include/asm-sh/fast_timer.h create mode 100644 include/linux/compiler-gcc+.h create mode 100644 include/linux/compiler-gcc2.h create mode 120000 include/linux/config.h create mode 100644 include/linux/dm270-id.h create mode 100644 include/linux/fast_timer.h create mode 100644 include/linux/ledman.h create mode 100644 include/linux/netfilter_ipv4/ipt_layer7.h create mode 100644 include/linux/netfilter_ipv4/ipt_time.h create mode 100644 include/linux/squashfs_fs.h create mode 100644 include/linux/squashfs_fs_i.h create mode 100644 include/linux/squashfs_fs_sb.h create mode 100644 include/linux/usb_isp1362.h create mode 100644 include/net/xfrmudp.h create mode 100755 linux.bin create mode 100644 net/ipsec/Makefile create mode 120000 net/ipsec/addrtoa.c create mode 120000 net/ipsec/addrtot.c create mode 120000 net/ipsec/addrtypeof.c create mode 120000 net/ipsec/adler32.c create mode 100644 net/ipsec/aes/Makefile create mode 120000 net/ipsec/anyaddr.c create mode 120000 net/ipsec/datatot.c create mode 120000 net/ipsec/deflate.c create mode 100644 net/ipsec/des/Makefile create mode 120000 net/ipsec/goodmask.c create mode 120000 net/ipsec/infblock.c create mode 120000 net/ipsec/infcodes.c create mode 120000 net/ipsec/inffast.c create mode 120000 net/ipsec/inflate.c create mode 120000 net/ipsec/inftrees.c create mode 120000 net/ipsec/infutil.c create mode 120000 net/ipsec/initaddr.c create mode 120000 net/ipsec/ipcomp.c create mode 120000 net/ipsec/ipsec_ah.c create mode 120000 net/ipsec/ipsec_alg.c create mode 120000 net/ipsec/ipsec_alg_cryptoapi.c create mode 120000 net/ipsec/ipsec_esp.c create mode 120000 net/ipsec/ipsec_init.c create mode 120000 net/ipsec/ipsec_ipcomp.c create mode 120000 net/ipsec/ipsec_ipip.c create mode 120000 net/ipsec/ipsec_kern24.c create mode 120000 net/ipsec/ipsec_life.c create mode 120000 net/ipsec/ipsec_mast.c create mode 120000 net/ipsec/ipsec_md5c.c create mode 120000 net/ipsec/ipsec_ocf.c create mode 120000 net/ipsec/ipsec_proc.c create mode 120000 net/ipsec/ipsec_radij.c create mode 120000 net/ipsec/ipsec_rcv.c create mode 120000 net/ipsec/ipsec_sa.c create mode 120000 net/ipsec/ipsec_sha1.c create mode 120000 net/ipsec/ipsec_snprintf.c create mode 120000 net/ipsec/ipsec_tunnel.c create mode 120000 net/ipsec/ipsec_xform.c create mode 120000 net/ipsec/ipsec_xmit.c create mode 120000 net/ipsec/match586.S create mode 120000 net/ipsec/match686.S create mode 120000 net/ipsec/pfkey_v2.c create mode 120000 net/ipsec/pfkey_v2_build.c create mode 120000 net/ipsec/pfkey_v2_debug.c create mode 120000 net/ipsec/pfkey_v2_ext_bits.c create mode 120000 net/ipsec/pfkey_v2_ext_process.c create mode 120000 net/ipsec/pfkey_v2_parse.c create mode 120000 net/ipsec/pfkey_v2_parser.c create mode 120000 net/ipsec/prng.c create mode 120000 net/ipsec/radij.c create mode 120000 net/ipsec/rangetoa.c create mode 120000 net/ipsec/satot.c create mode 120000 net/ipsec/subnetof.c create mode 120000 net/ipsec/subnettoa.c create mode 120000 net/ipsec/sysctl_net_ipsec.c create mode 120000 net/ipsec/trees.c create mode 120000 net/ipsec/ultoa.c create mode 120000 net/ipsec/ultot.c create mode 120000 net/ipsec/version.in.c create mode 120000 net/ipsec/zutil.c create mode 100644 net/ipv4/netfilter/ipt_layer7.c create mode 100644 net/ipv4/netfilter/ipt_time.c create mode 100644 net/ipv4/netfilter/regexp/regexp.c create mode 100644 net/ipv4/netfilter/regexp/regexp.h create mode 100644 net/ipv4/netfilter/regexp/regmagic.h create mode 100644 net/ipv4/netfilter/regexp/regsub.c diff --git a/CREDITS b/CREDITS index ccd4f9f4..4de89a88 100644 --- a/CREDITS +++ b/CREDITS @@ -615,6 +615,15 @@ S: Stanford University S: Stanford, California 94305 S: USA +N: Hyok S. Choi +W: http://opensrc.sec.samsung.com/ +E: hyok.choi@samsung.com +D: Author and Maintainer of uClinux/ARM port (MPU/noMMU) +D: Author of DCC(JTAG1) serial console emulation driver +S: Samsung Electronics Co.,Ltd. +S: Suwon, Gyeonggi, 443-742 +S: South Korea + N: Randolph Chung E: tausq@debian.org D: Linux/PA-RISC hacker diff --git a/MAINTAINERS b/MAINTAINERS index e182992f..6131c637 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -825,6 +825,13 @@ P: Guennadi Liakhovetski M: g.liakhovetski@gmx.de S: Maintained +DCC(JTAG) Console driver +P: Hyok S. Choi +M: hyok.choi@samsung.com +M: hyok.choi@gmail.com +W: http://opensrc.sec.samsung.com/ +S: Maintained + DCCP PROTOCOL P: Arnaldo Carvalho de Melo M: acme@mandriva.com @@ -3335,6 +3342,12 @@ W: http://www.uclinux.org/ L: uclinux-dev@uclinux.org (subscribers-only) S: Maintained +UCLINUX FOR ARM +P: Hyok S. Choi +M: hyok.choi@samsung.com +W: http://opensrc.sec.samsung.com/ +S: Maintained + UCLINUX FOR NEC V850 P: Miles Bader M: uclinux-v850@lsi.nec.co.jp diff --git a/Makefile b/Makefile index aef96259..1bd53202 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 19 EXTRAVERSION = +EXTRAVERSION = -uc1 NAME=Avast! A bilge rat! # *DOCUMENTATION* @@ -563,12 +564,12 @@ core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ - $(net-y) $(net-m) $(libs-y) $(libs-m))) + $(net-y) $(net-m) $(libs-y) $(libs-m) $(EXTRA_MODULE_DIRS))) vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \ $(init-n) $(init-) \ $(core-n) $(core-) $(drivers-n) $(drivers-) \ - $(net-n) $(net-) $(libs-n) $(libs-)))) + $(net-n) $(net-) $(libs-n) $(libs-) $(EXTRA_MODULE_DIRS)))) init-y := $(patsubst %/, %/built-in.o, $(init-y)) core-y := $(patsubst %/, %/built-in.o, $(core-y)) @@ -979,9 +980,8 @@ _modinst_: sleep 1; \ fi @rm -rf $(MODLIB)/kernel - @rm -f $(MODLIB)/source @mkdir -p $(MODLIB)/kernel - @ln -s $(srctree) $(MODLIB)/source + cd $(INSTALL_MOD_PATH)/lib/modules && ln -s $(KERNELRELEASE) 2.6.9-MoXaRt @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \ rm -f $(MODLIB)/build ; \ ln -s $(objtree) $(MODLIB)/build ; \ @@ -996,11 +996,11 @@ _modinst_: ifeq "$(strip $(INSTALL_MOD_PATH))" "" depmod_opts := else -depmod_opts := -b $(INSTALL_MOD_PATH) -r +depmod_opts := -b $(INSTALL_MOD_PATH)/lib/modules -r endif PHONY += _modinst_post _modinst_post: _modinst_ - if [ -r System.map -a -x $(DEPMOD) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi + if [ -r System.map -a -x $(word 1, $(DEPMOD)) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi else # CONFIG_MODULES diff --git a/Makefile-bak-02162007 b/Makefile-bak-02162007 new file mode 100644 index 00000000..ce689d5b --- /dev/null +++ b/Makefile-bak-02162007 @@ -0,0 +1,1491 @@ +VERSION = 2 +PATCHLEVEL = 6 +SUBLEVEL = 19 +EXTRAVERSION = +EXTRAVERSION = -uc1 +NAME=Avast! A bilge rat! + +# *DOCUMENTATION* +# To see a list of typical targets execute "make help" +# More info can be located in ./README +# Comments in this file are targeted only to the developer, do not +# expect to learn how to build the kernel reading this file. + +# Do not print "Entering directory ..." +MAKEFLAGS += --no-print-directory + +# We are using a recursive build, so we need to do a little thinking +# to get the ordering right. +# +# Most importantly: sub-Makefiles should only ever modify files in +# their own directory. If in some directory we have a dependency on +# a file in another dir (which doesn't happen often, but it's often +# unavoidable when linking the built-in.o targets which finally +# turn into vmlinux), we will call a sub make in that other dir, and +# after that we are sure that everything which is in that other dir +# is now up to date. +# +# The only cases where we need to modify files which have global +# effects are thus separated out and done before the recursive +# descending is started. They are now explicitly listed as the +# prepare rule. + +# To put more focus on warnings, be less verbose as default +# Use 'make V=1' to see the full commands + +ifdef V + ifeq ("$(origin V)", "command line") + KBUILD_VERBOSE = $(V) + endif +endif +ifndef KBUILD_VERBOSE + KBUILD_VERBOSE = 0 +endif + +# Call a source code checker (by default, "sparse") as part of the +# C compilation. +# +# Use 'make C=1' to enable checking of only re-compiled files. +# Use 'make C=2' to enable checking of *all* source files, regardless +# of whether they are re-compiled or not. +# +# See the file "Documentation/sparse.txt" for more details, including +# where to get the "sparse" utility. + +ifdef C + ifeq ("$(origin C)", "command line") + KBUILD_CHECKSRC = $(C) + endif +endif +ifndef KBUILD_CHECKSRC + KBUILD_CHECKSRC = 0 +endif + +# Use make M=dir to specify directory of external module to build +# Old syntax make ... SUBDIRS=$PWD is still supported +# Setting the environment variable KBUILD_EXTMOD take precedence +ifdef SUBDIRS + KBUILD_EXTMOD ?= $(SUBDIRS) +endif +ifdef M + ifeq ("$(origin M)", "command line") + KBUILD_EXTMOD := $(M) + endif +endif + + +# kbuild supports saving output files in a separate directory. +# To locate output files in a separate directory two syntaxes are supported. +# In both cases the working directory must be the root of the kernel src. +# 1) O= +# Use "make O=dir/to/store/output/files/" +# +# 2) Set KBUILD_OUTPUT +# Set the environment variable KBUILD_OUTPUT to point to the directory +# where the output files shall be placed. +# export KBUILD_OUTPUT=dir/to/store/output/files/ +# make +# +# The O= assignment takes precedence over the KBUILD_OUTPUT environment +# variable. + + +# KBUILD_SRC is set on invocation of make in OBJ directory +# KBUILD_SRC is not intended to be used by the regular user (for now) +ifeq ($(KBUILD_SRC),) + +# OK, Make called in directory where kernel src resides +# Do we want to locate output files in a separate directory? +ifdef O + ifeq ("$(origin O)", "command line") + KBUILD_OUTPUT := $(O) + endif +endif + +# That's our default target when none is given on the command line +PHONY := _all +_all: + +ifneq ($(KBUILD_OUTPUT),) +# Invoke a second make in the output directory, passing relevant variables +# check that the output directory actually exists +saved-output := $(KBUILD_OUTPUT) +KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd) +$(if $(KBUILD_OUTPUT),, \ + $(error output directory "$(saved-output)" does not exist)) + +PHONY += $(MAKECMDGOALS) + +$(filter-out _all,$(MAKECMDGOALS)) _all: + $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \ + KBUILD_SRC=$(CURDIR) \ + KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@ + +# Leave processing to above invocation of make +skip-makefile := 1 +endif # ifneq ($(KBUILD_OUTPUT),) +endif # ifeq ($(KBUILD_SRC),) + +# We process the rest of the Makefile if this is the final invocation of make +ifeq ($(skip-makefile),) + +# If building an external module we do not care about the all: rule +# but instead _all depend on modules +PHONY += all +ifeq ($(KBUILD_EXTMOD),) +_all: all +else +_all: modules +endif + +srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR)) +TOPDIR := $(srctree) +# FIXME - TOPDIR is obsolete, use srctree/objtree +objtree := $(CURDIR) +src := $(srctree) +obj := $(objtree) + +VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) + +export srctree objtree VPATH TOPDIR + + +# SUBARCH tells the usermode build what the underlying arch is. That is set +# first, and if a usermode build is happening, the "ARCH=um" on the command +# line overrides the setting of ARCH below. If a native build is happening, +# then ARCH is assigned, getting whatever value it gets normally, and +# SUBARCH is subsequently ignored. + +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ ) + +# Cross compiling and selecting different set of gcc/bin-utils +# --------------------------------------------------------------------------- +# +# When performing cross compilation for other architectures ARCH shall be set +# to the target architecture. (See arch/* for the possibilities). +# ARCH can be set during invocation of make: +# make ARCH=ia64 +# Another way is to have ARCH set in the environment. +# The default ARCH is the host where make is executed. + +# CROSS_COMPILE specify the prefix used for all executables used +# during compilation. Only gcc and related bin-utils executables +# are prefixed with $(CROSS_COMPILE). +# CROSS_COMPILE can be set on the command line +# make CROSS_COMPILE=ia64-linux- +# Alternatively CROSS_COMPILE can be set in the environment. +# Default value for CROSS_COMPILE is not to prefix executables +# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= + +# Architecture as present in compile.h +UTS_MACHINE := $(ARCH) + +KCONFIG_CONFIG ?= .config + +# SHELL used by kbuild +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) + +HOSTCC = gcc +HOSTCXX = g++ +HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCXXFLAGS = -O2 + +# Decide whether to build built-in, modular, or both. +# Normally, just do built-in. + +KBUILD_MODULES := +KBUILD_BUILTIN := 1 + +# If we have only "make modules", don't compile built-in objects. +# When we're building modules with modversions, we need to consider +# the built-in objects during the descend as well, in order to +# make sure the checksums are up to date before we record them. + +ifeq ($(MAKECMDGOALS),modules) + KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) +endif + +# If we have "make modules", compile modules +# in addition to whatever we do anyway. +# Just "make" or "make all" shall build modules as well + +ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) + KBUILD_MODULES := 1 +endif + +ifeq ($(MAKECMDGOALS),) + KBUILD_MODULES := 1 +endif + +export KBUILD_MODULES KBUILD_BUILTIN +export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD + +# Beautify output +# --------------------------------------------------------------------------- +# +# Normally, we echo the whole command before executing it. By making +# that echo $($(quiet)$(cmd)), we now have the possibility to set +# $(quiet) to choose other forms of output instead, e.g. +# +# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@ +# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< +# +# If $(quiet) is empty, the whole command will be printed. +# If it is set to "quiet_", only the short version will be printed. +# If it is set to "silent_", nothing will be printed at all, since +# the variable $(silent_cmd_cc_o_c) doesn't exist. +# +# A simple variant is to prefix commands with $(Q) - that's useful +# for commands that shall be hidden in non-verbose mode. +# +# $(Q)ln $@ :< +# +# If KBUILD_VERBOSE equals 0 then the above command will be hidden. +# If KBUILD_VERBOSE equals 1 then the above command is displayed. + +ifeq ($(KBUILD_VERBOSE),1) + quiet = + Q = +else + quiet=quiet_ + Q = @ +endif + +# If the user is running make -s (silent mode), suppress echoing of +# commands + +ifneq ($(findstring s,$(MAKEFLAGS)),) + quiet=silent_ +endif + +export quiet Q KBUILD_VERBOSE + + +# Look for make include files relative to root of kernel src +MAKEFLAGS += --include-dir=$(srctree) + +# We need some generic definitions +include $(srctree)/scripts/Kbuild.include + +# Do not use make's built-in rules and variables +# This increases performance and avoid hard-to-debug behavour +MAKEFLAGS += -rR + +# Make variables (CC, etc...) + +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +AWK = awk +GENKSYMS = scripts/genksyms/genksyms +DEPMOD = /sbin/depmod +KALLSYMS = scripts/kallsyms +PERL = perl +CHECK = sparse + +CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) +MODFLAGS = -DMODULE +CFLAGS_MODULE = $(MODFLAGS) +AFLAGS_MODULE = $(MODFLAGS) +LDFLAGS_MODULE = -r +CFLAGS_KERNEL = +AFLAGS_KERNEL = + + +# Use LINUXINCLUDE when you must reference the include/ directory. +# Needed to be compatible with the O= option +LINUXINCLUDE := -Iinclude \ + $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ + -include include/linux/autoconf.h + +CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) + +CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ + -fno-strict-aliasing -fno-common +AFLAGS := -D__ASSEMBLY__ + +# Read KERNELRELEASE from include/config/kernel.release (if it exists) +KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) +KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION +export ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC +export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE +export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS + +export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS +export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE +export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE + +# When compiling out-of-tree modules, put MODVERDIR in the module +# tree rather than in the kernel tree. The kernel tree might +# even be read-only. +export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions + +# Files to ignore in find ... statements + +RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git + +# =========================================================================== +# Rules shared between *config targets and build targets + +# Basic helpers built in scripts/ +PHONY += scripts_basic +scripts_basic: + $(Q)$(MAKE) $(build)=scripts/basic + +# To avoid any implicit rule to kick in, define an empty command. +scripts/basic/%: scripts_basic ; + +PHONY += outputmakefile +# outputmakefile generates a Makefile in the output directory, if using a +# separate output directory. This allows convenient use of make in the +# output directory. +outputmakefile: +ifneq ($(KBUILD_SRC),) + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ + $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) +endif + +# To make sure we do not include .config for any of the *config targets +# catch them early, and hand them over to scripts/kconfig/Makefile +# It is allowed to specify more targets when calling make, including +# mixing *config targets and build targets. +# For example 'make oldconfig all'. +# Detect when mixed targets is specified, and make a second invocation +# of make so .config is not included in this case either (for *config). + +no-dot-config-targets := clean mrproper distclean \ + cscope TAGS tags help %docs check% \ + include/linux/version.h headers_% \ + kernelrelease kernelversion + +config-targets := 0 +mixed-targets := 0 +dot-config := 1 + +ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) + dot-config := 0 + endif +endif + +ifeq ($(KBUILD_EXTMOD),) + ifneq ($(filter config %config,$(MAKECMDGOALS)),) + config-targets := 1 + ifneq ($(filter-out config %config,$(MAKECMDGOALS)),) + mixed-targets := 1 + endif + endif +endif + +ifeq ($(mixed-targets),1) +# =========================================================================== +# We're called with mixed targets (*config and build targets). +# Handle them one by one. + +%:: FORCE + $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@ + +else +ifeq ($(config-targets),1) +# =========================================================================== +# *config targets only - make sure prerequisites are updated, and descend +# in scripts/kconfig to make the *config target + +# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed. +# KBUILD_DEFCONFIG may point out an alternative default configuration +# used for 'make defconfig' +include $(srctree)/arch/$(ARCH)/Makefile +export KBUILD_DEFCONFIG + +config %config: scripts_basic outputmakefile FORCE + $(Q)mkdir -p include/linux include/config + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + +else +# =========================================================================== +# Build targets only - this includes vmlinux, arch specific targets, clean +# targets and others. In general all targets except *config targets. + +ifeq ($(KBUILD_EXTMOD),) +# Additional helpers built in scripts/ +# Carefully list dependencies so we do not try to build scripts twice +# in parallel +PHONY += scripts +scripts: scripts_basic include/config/auto.conf + $(Q)$(MAKE) $(build)=$(@) + +# Objects we will link into vmlinux / subdirs we need to visit +init-y := init/ +drivers-y := drivers/ sound/ +net-y := net/ +libs-y := lib/ +core-y := usr/ +endif # KBUILD_EXTMOD + +ifeq ($(dot-config),1) +# Read in config +-include include/config/auto.conf + +ifeq ($(KBUILD_EXTMOD),) +# Read in dependencies to all Kconfig* files, make sure to run +# oldconfig if changes are detected. +-include include/config/auto.conf.cmd + +# To avoid any implicit rule to kick in, define an empty command +$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; + +# If .config is newer than include/config/auto.conf, someone tinkered +# with it and forgot to run make oldconfig. +# if auto.conf.cmd is missing then we are probably in a cleaned tree so +# we execute the config step to be sure to catch updated Kconfig files +include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd + $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig +else +# external modules needs include/linux/autoconf.h and include/config/auto.conf +# but do not care if they are up-to-date. Use auto.conf to trigger the test +PHONY += include/config/auto.conf + +include/config/auto.conf: + $(Q)test -e include/linux/autoconf.h -a -e $@ || ( \ + echo; \ + echo " ERROR: Kernel configuration is invalid."; \ + echo " include/linux/autoconf.h or $@ are missing."; \ + echo " Run 'make oldconfig && make prepare' on kernel src to fix it."; \ + echo; \ + /bin/false) + +endif # KBUILD_EXTMOD + +else +# Dummy target needed, because used as prerequisite +include/config/auto.conf: ; +endif # $(dot-config) + +# The all: target is the default when no target is given on the +# command line. +# This allow a user to issue only 'make' to build a kernel including modules +# Defaults vmlinux but it is usually overridden in the arch makefile +all: vmlinux + +ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +CFLAGS += -Os +else +CFLAGS += -O2 +endif + +include $(srctree)/arch/$(ARCH)/Makefile + +ifdef CONFIG_FRAME_POINTER +CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,) +else +CFLAGS += -fomit-frame-pointer +endif + +ifdef CONFIG_UNWIND_INFO +CFLAGS += -fasynchronous-unwind-tables +LDFLAGS_vmlinux += --eh-frame-hdr +endif + +ifdef CONFIG_DEBUG_INFO +CFLAGS += -g +endif + +# Force gcc to behave correct even for buggy distributions +CFLAGS += $(call cc-option, -fno-stack-protector) + +# arch Makefile may override CC so keep this after arch Makefile is included +NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) +CHECKFLAGS += $(NOSTDINC_FLAGS) + +# warn about C99 declaration after statement +CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) + +# disable pointer signed / unsigned warnings in gcc 4.0 +CFLAGS += $(call cc-option,-Wno-pointer-sign,) + +# Default kernel image to build when no specific target is given. +# KBUILD_IMAGE may be overruled on the command line or +# set in the environment +# Also any assignments in arch/$(ARCH)/Makefile take precedence over +# this default value +export KBUILD_IMAGE ?= vmlinux + +# +# INSTALL_PATH specifies where to place the updated kernel and system map +# images. Default is /boot, but you can set it to other values +export INSTALL_PATH ?= /boot + +# +# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +# relocations required by build roots. This is not defined in the +# makefile but the argument can be passed to make if needed. +# + +MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) +export MODLIB + +# +# INSTALL_MOD_STRIP, if defined, will cause modules to be +# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then +# the default option --strip-debug will be used. Otherwise, +# INSTALL_MOD_STRIP will used as the options to the strip command. + +ifdef INSTALL_MOD_STRIP +ifeq ($(INSTALL_MOD_STRIP),1) +mod_strip_cmd = $(STRIP) --strip-debug +else +mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP) +endif # INSTALL_MOD_STRIP=1 +else +mod_strip_cmd = true +endif # INSTALL_MOD_STRIP +export mod_strip_cmd + + +ifeq ($(KBUILD_EXTMOD),) +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ + +vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ + $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ + $(net-y) $(net-m) $(libs-y) $(libs-m) $(EXTRA_MODULE_DIRS))) + +vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \ + $(init-n) $(init-) \ + $(core-n) $(core-) $(drivers-n) $(drivers-) \ + $(net-n) $(net-) $(libs-n) $(libs-) $(EXTRA_MODULE_DIRS)))) + +init-y := $(patsubst %/, %/built-in.o, $(init-y)) +core-y := $(patsubst %/, %/built-in.o, $(core-y)) +drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) +net-y := $(patsubst %/, %/built-in.o, $(net-y)) +libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) +libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) +libs-y := $(libs-y1) $(libs-y2) + +# Build vmlinux +# --------------------------------------------------------------------------- +# vmlinux is built from the objects selected by $(vmlinux-init) and +# $(vmlinux-main). Most are built-in.o files from top-level directories +# in the kernel tree, others are specified in arch/$(ARCH)Makefile. +# Ordering when linking is important, and $(vmlinux-init) must be first. +# +# vmlinux +# ^ +# | +# +-< $(vmlinux-init) +# | +--< init/version.o + more +# | +# +--< $(vmlinux-main) +# | +--< driver/built-in.o mm/built-in.o + more +# | +# +-< kallsyms.o (see description in CONFIG_KALLSYMS section) +# +# vmlinux version (uname -v) cannot be updated during normal +# descending-into-subdirs phase since we do not yet know if we need to +# update vmlinux. +# Therefore this step is delayed until just before final link of vmlinux - +# except in the kallsyms case where it is done just before adding the +# symbols to the kernel. +# +# System.map is generated to document addresses of all kernel symbols + +vmlinux-init := $(head-y) $(init-y) +vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) +vmlinux-all := $(vmlinux-init) $(vmlinux-main) +vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds + +# Rule to link vmlinux - also used during CONFIG_KALLSYMS +# May be overridden by arch/$(ARCH)/Makefile +quiet_cmd_vmlinux__ ?= LD $@ + cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \ + -T $(vmlinux-lds) $(vmlinux-init) \ + --start-group $(vmlinux-main) --end-group \ + $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^) + +# Generate new vmlinux version +quiet_cmd_vmlinux_version = GEN .version + cmd_vmlinux_version = set -e; \ + if [ ! -r .version ]; then \ + rm -f .version; \ + echo 1 >.version; \ + else \ + mv .version .old_version; \ + expr 0$$(cat .old_version) + 1 >.version; \ + fi; \ + $(MAKE) $(build)=init + +# Generate System.map +quiet_cmd_sysmap = SYSMAP + cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap + +# Link of vmlinux +# If CONFIG_KALLSYMS is set .version is already updated +# Generate System.map and verify that the content is consistent +# Use + in front of the vmlinux_version rule to silent warning with make -j2 +# First command is ':' to allow us to use + in front of the rule +define rule_vmlinux__ + : + $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version)) + + $(call cmd,vmlinux__) + $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd + + $(Q)$(if $($(quiet)cmd_sysmap), \ + echo ' $($(quiet)cmd_sysmap) System.map' &&) \ + $(cmd_sysmap) $@ System.map; \ + if [ $$? -ne 0 ]; then \ + rm -f $@; \ + /bin/false; \ + fi; + $(verify_kallsyms) +endef + + +ifdef CONFIG_KALLSYMS +# Generate section listing all symbols and add it into vmlinux $(kallsyms.o) +# It's a three stage process: +# o .tmp_vmlinux1 has all symbols and sections, but __kallsyms is +# empty +# Running kallsyms on that gives us .tmp_kallsyms1.o with +# the right size - vmlinux version (uname -v) is updated during this step +# o .tmp_vmlinux2 now has a __kallsyms section of the right size, +# but due to the added section, some addresses have shifted. +# From here, we generate a correct .tmp_kallsyms2.o +# o The correct .tmp_kallsyms2.o is linked into the final vmlinux. +# o Verify that the System.map from vmlinux matches the map from +# .tmp_vmlinux2, just in case we did not generate kallsyms correctly. +# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using +# .tmp_vmlinux3 and .tmp_kallsyms3.o. This is only meant as a +# temporary bypass to allow the kernel to be built while the +# maintainers work out what went wrong with kallsyms. + +ifdef CONFIG_KALLSYMS_EXTRA_PASS +last_kallsyms := 3 +else +last_kallsyms := 2 +endif + +kallsyms.o := .tmp_kallsyms$(last_kallsyms).o + +define verify_kallsyms + $(Q)$(if $($(quiet)cmd_sysmap), \ + echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \ + $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map + $(Q)cmp -s System.map .tmp_System.map || \ + (echo Inconsistent kallsyms data; \ + echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \ + rm .tmp_kallsyms* ; /bin/false ) +endef + +# Update vmlinux version before link +# Use + in front of this rule to silent warning about make -j1 +# First command is ':' to allow us to use + in front of this rule +cmd_ksym_ld = $(cmd_vmlinux__) +define rule_ksym_ld + : + +$(call cmd,vmlinux_version) + $(call cmd,vmlinux__) + $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd +endef + +# Generate .S file with all kernel symbols +quiet_cmd_kallsyms = KSYM $@ + cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \ + $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@ + +.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE + $(call if_changed_dep,as_o_S) + +.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS) + $(call cmd,kallsyms) + +# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version +.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE + $(call if_changed_rule,ksym_ld) + +.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE + $(call if_changed,vmlinux__) + +.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE + $(call if_changed,vmlinux__) + +# Needs to visit scripts/ before $(KALLSYMS) can be used. +$(KALLSYMS): scripts ; + +# Generate some data for debugging strange kallsyms problems +debug_kallsyms: .tmp_map$(last_kallsyms) + +.tmp_map%: .tmp_vmlinux% FORCE + ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@ + +.tmp_map3: .tmp_map2 + +.tmp_map2: .tmp_map1 + +endif # ifdef CONFIG_KALLSYMS + +# vmlinux image - including updated kernel symbols +vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE +ifdef CONFIG_HEADERS_CHECK + $(Q)$(MAKE) -f $(srctree)/Makefile headers_check +endif + $(call if_changed_rule,vmlinux__) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@ + $(Q)rm -f .old_version + +# The actual objects are generated when descending, +# make sure no implicit rule kicks in +$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; + +# Handle descending into subdirectories listed in $(vmlinux-dirs) +# Preset locale variables to speed up the build process. Limit locale +# tweaks to this spot to avoid wrong language settings when running +# make menuconfig etc. +# Error messages still appears in the original language + +PHONY += $(vmlinux-dirs) +$(vmlinux-dirs): prepare scripts + $(Q)$(MAKE) $(build)=$@ + +# Build the kernel release string +# +# The KERNELRELEASE value built here is stored in the file +# include/config/kernel.release, and is used when executing several +# make targets, such as "make install" or "make modules_install." +# +# The eventual kernel release string consists of the following fields, +# shown in a hierarchical format to show how smaller parts are concatenated +# to form the larger and final value, with values coming from places like +# the Makefile, kernel config options, make command line options and/or +# SCM tag information. +# +# $(KERNELVERSION) +# $(VERSION) eg, 2 +# $(PATCHLEVEL) eg, 6 +# $(SUBLEVEL) eg, 18 +# $(EXTRAVERSION) eg, -rc6 +# $(localver-full) +# $(localver) +# localversion* (all localversion* files) +# $(CONFIG_LOCALVERSION) (from kernel config setting) +# $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set) +# ./scripts/setlocalversion (SCM tag, if one exists) +# $(LOCALVERSION) (from make command line if provided) +# +# Note how the final $(localver-auto) string is included *only* if the +# kernel config option CONFIG_LOCALVERSION_AUTO is selected. Also, at the +# moment, only git is supported but other SCMs can edit the script +# scripts/setlocalversion and add the appropriate checks as needed. + +nullstring := +space := $(nullstring) # end of line + +___localver = $(objtree)/localversion* $(srctree)/localversion* +__localver = $(sort $(wildcard $(___localver))) +# skip backup files (containing '~') +_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f))) + +localver = $(subst $(space),, \ + $(shell cat /dev/null $(_localver)) \ + $(patsubst "%",%,$(CONFIG_LOCALVERSION))) + +# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called +# and if the SCM is know a tag from the SCM is appended. +# The appended tag is determined by the SCM used. +# +# Currently, only git is supported. +# Other SCMs can edit scripts/setlocalversion and add the appropriate +# checks as needed. +ifdef CONFIG_LOCALVERSION_AUTO + _localver-auto = $(shell $(CONFIG_SHELL) \ + $(srctree)/scripts/setlocalversion $(srctree)) + localver-auto = $(LOCALVERSION)$(_localver-auto) +endif + +localver-full = $(localver)$(localver-auto) + +# Store (new) KERNELRELASE string in include/config/kernel.release +kernelrelease = $(KERNELVERSION)$(localver-full) +include/config/kernel.release: include/config/auto.conf FORCE + $(Q)rm -f $@ + $(Q)echo $(kernelrelease) > $@ + + +# Things we need to do before we recursively start building the kernel +# or the modules are listed in "prepare". +# A multi level approach is used. prepareN is processed before prepareN-1. +# archprepare is used in arch Makefiles and when processed asm symlink, +# version.h and scripts_basic is processed / created. + +# Listed in dependency order +PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 + +# prepare-all is deprecated, use prepare as valid replacement +PHONY += prepare-all + +# prepare3 is used to check if we are building in a separate output directory, +# and if so do: +# 1) Check that make has not been executed in the kernel src $(srctree) +# 2) Create the include2 directory, used for the second asm symlink +prepare3: include/config/kernel.release +ifneq ($(KBUILD_SRC),) + @echo ' Using $(srctree) as source for kernel' + $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ + echo " $(srctree) is not clean, please run 'make mrproper'";\ + echo " in the '$(srctree)' directory.";\ + /bin/false; \ + fi; + $(Q)if [ ! -d include2 ]; then mkdir -p include2; fi; + $(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm +endif + +# prepare2 creates a makefile if using a separate output directory +prepare2: prepare3 outputmakefile + +prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \ + include/asm include/config/auto.conf +ifneq ($(KBUILD_MODULES),) + $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* +endif + +archprepare: prepare1 scripts_basic + +prepare0: archprepare FORCE + $(Q)$(MAKE) $(build)=. + +# All the preparing.. +prepare prepare-all: prepare0 + +# Leave this as default for preprocessing vmlinux.lds.S, which is now +# done in arch/$(ARCH)/kernel/Makefile + +export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) + +# FIXME: The asm symlink changes when $(ARCH) changes. That's +# hard to detect, but I suppose "make mrproper" is a good idea +# before switching between archs anyway. + +include/asm: + @echo ' SYMLINK $@ -> include/asm-$(ARCH)' + $(Q)if [ ! -d include ]; then mkdir -p include; fi; + @ln -fsn asm-$(ARCH) $@ + +# Generate some files +# --------------------------------------------------------------------------- + +# KERNELRELEASE can change from a few different places, meaning version.h +# needs to be updated, so this check is forced on all builds + +uts_len := 64 +define filechk_utsrelease.h + if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \ + echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \ + exit 1; \ + fi; \ + (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";) +endef + +define filechk_version.h + (echo \#define LINUX_VERSION_CODE $(shell \ + expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL)); \ + echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';) +endef + +include/linux/version.h: $(srctree)/Makefile FORCE + $(call filechk,version.h) + +include/linux/utsrelease.h: include/config/kernel.release FORCE + $(call filechk,utsrelease.h) + +# --------------------------------------------------------------------------- + +PHONY += depend dep +depend dep: + @echo '*** Warning: make $@ is unnecessary now.' + +# --------------------------------------------------------------------------- +# Kernel headers +INSTALL_HDR_PATH=$(objtree)/usr +export INSTALL_HDR_PATH + +HDRARCHES=$(filter-out generic,$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild))) + +PHONY += headers_install_all +headers_install_all: include/linux/version.h scripts_basic FORCE + $(Q)$(MAKE) $(build)=scripts scripts/unifdef + $(Q)for arch in $(HDRARCHES); do \ + $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch ;\ + done + +PHONY += headers_install +headers_install: include/linux/version.h scripts_basic FORCE + @if [ ! -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \ + echo '*** Error: Headers not exportable for this architecture ($(ARCH))'; \ + exit 1 ; fi + $(Q)$(MAKE) $(build)=scripts scripts/unifdef + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include + +PHONY += headers_check +headers_check: headers_install + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1 + +# --------------------------------------------------------------------------- +# Modules + +ifdef CONFIG_MODULES + +# By default, build modules as well + +all: modules + +# Build modules + +PHONY += modules +modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) + @echo ' Building modules, stage 2.'; + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + + +# Target to prepare building external modules +PHONY += modules_prepare +modules_prepare: prepare scripts + +# Target to install modules +PHONY += modules_install +modules_install: _modinst_ _modinst_post + +PHONY += _modinst_ +_modinst_: + @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \ + echo "Warning: you may need to install module-init-tools"; \ + echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ + sleep 1; \ + fi + @rm -rf $(MODLIB)/kernel + @rm -f $(MODLIB)/source + @mkdir -p $(MODLIB)/kernel + @ln -s $(srctree) $(MODLIB)/source + @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \ + rm -f $(MODLIB)/build ; \ + ln -s $(objtree) $(MODLIB)/build ; \ + fi + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst + +# If System.map exists, run depmod. This deliberately does not have a +# dependency on System.map since that would run the dependency tree on +# vmlinux. This depmod is only for convenience to give the initial +# boot a modules.dep even before / is mounted read-write. However the +# boot script depmod is the master version. +ifeq "$(strip $(INSTALL_MOD_PATH))" "" +depmod_opts := +else +depmod_opts := -b $(INSTALL_MOD_PATH)/lib/modules -r +endif +PHONY += _modinst_post +_modinst_post: _modinst_ + if [ -r System.map -a -x $(word 1, $(DEPMOD)) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi + +else # CONFIG_MODULES + +# Modules not configured +# --------------------------------------------------------------------------- + +modules modules_install: FORCE + @echo + @echo "The present kernel configuration has modules disabled." + @echo "Type 'make config' and enable loadable module support." + @echo "Then build a kernel with module support enabled." + @echo + @exit 1 + +endif # CONFIG_MODULES + +### +# Cleaning is done on three levels. +# make clean Delete most generated files +# Leave enough to build external modules +# make mrproper Delete the current configuration, and all generated files +# make distclean Remove editor backup files, patch leftover files and the like + +# Directories & files removed with 'make clean' +CLEAN_DIRS += $(MODVERDIR) +CLEAN_FILES += vmlinux System.map \ + .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map + +# Directories & files removed with 'make mrproper' +MRPROPER_DIRS += include/config include2 usr/include +MRPROPER_FILES += .config .config.old include/asm .version .old_version \ + include/linux/autoconf.h include/linux/version.h \ + include/linux/utsrelease.h \ + Module.symvers tags TAGS cscope* + +# clean - Delete most, but leave enough to build external modules +# +clean: rm-dirs := $(CLEAN_DIRS) +clean: rm-files := $(CLEAN_FILES) +clean-dirs := $(addprefix _clean_,$(srctree) $(vmlinux-alldirs)) + +PHONY += $(clean-dirs) clean archclean +$(clean-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) + +clean: archclean $(clean-dirs) + $(call cmd,rmdirs) + $(call cmd,rmfiles) + @find . $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ + -o -name '*.symtypes' \) \ + -type f -print | xargs rm -f + +# mrproper - Delete all generated files, including .config +# +mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) +mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) +mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts) + +PHONY += $(mrproper-dirs) mrproper archmrproper +$(mrproper-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@) + +mrproper: clean archmrproper $(mrproper-dirs) + $(call cmd,rmdirs) + $(call cmd,rmfiles) + +# distclean +# +PHONY += distclean + +distclean: mrproper + @find $(srctree) $(RCS_FIND_IGNORE) \ + \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -size 0 \ + -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ + -type f -print | xargs rm -f + + +# Packaging of the kernel to various formats +# --------------------------------------------------------------------------- +# rpm target kept for backward compatibility +package-dir := $(srctree)/scripts/package + +%pkg: include/config/kernel.release FORCE + $(Q)$(MAKE) $(build)=$(package-dir) $@ +rpm: include/config/kernel.release FORCE + $(Q)$(MAKE) $(build)=$(package-dir) $@ + + +# Brief documentation of the typical targets used +# --------------------------------------------------------------------------- + +boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig) +boards := $(notdir $(boards)) + +help: + @echo 'Cleaning targets:' + @echo ' clean - remove most generated files but keep the config and' + @echo ' enough build support to build external modules' + @echo ' mrproper - remove all generated files + config + various backup files' + @echo ' distclean - mrproper + remove editor backup and patch files' + @echo '' + @echo 'Configuration targets:' + @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help + @echo '' + @echo 'Other generic targets:' + @echo ' all - Build all targets marked with [*]' + @echo '* vmlinux - Build the bare kernel' + @echo '* modules - Build all modules' + @echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)' + @echo ' dir/ - Build all files in dir and below' + @echo ' dir/file.[ois] - Build specified target only' + @echo ' dir/file.ko - Build module including final link' + @echo ' rpm - Build a kernel as an RPM package' + @echo ' tags/TAGS - Generate tags file for editors' + @echo ' cscope - Generate cscope index' + @echo ' kernelrelease - Output the release version string' + @echo ' kernelversion - Output the version stored in Makefile' + @if [ -r include/asm-$(ARCH)/Kbuild ]; then \ + echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \ + fi + @echo ' (default: $(INSTALL_HDR_PATH))' + @echo '' + @echo 'Static analysers' + @echo ' checkstack - Generate a list of stack hogs' + @echo ' namespacecheck - Name space analysis on compiled kernel' + @if [ -r include/asm-$(ARCH)/Kbuild ]; then \ + echo ' headers_check - Sanity check on exported headers'; \ + fi + @echo '' + @echo 'Kernel packaging:' + @$(MAKE) $(build)=$(package-dir) help + @echo '' + @echo 'Documentation targets:' + @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp + @echo '' + @echo 'Architecture specific targets ($(ARCH)):' + @$(if $(archhelp),$(archhelp),\ + echo ' No architecture specific help defined for $(ARCH)') + @echo '' + @$(if $(boards), \ + $(foreach b, $(boards), \ + printf " %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \ + echo '') + + @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' + @echo ' make V=2 [targets] 2 => give reason for rebuild of target' + @echo ' make O=dir [targets] Locate all output files in "dir", including .config' + @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' + @echo ' make C=2 [targets] Force check of all c source with $$CHECK' + @echo '' + @echo 'Execute "make" or "make all" to build all targets marked with [*] ' + @echo 'For further info see the ./README file' + + +# Documentation targets +# --------------------------------------------------------------------------- +%docs: scripts_basic FORCE + $(Q)$(MAKE) $(build)=Documentation/DocBook $@ + +else # KBUILD_EXTMOD + +### +# External module support. +# When building external modules the kernel used as basis is considered +# read-only, and no consistency checks are made and the make +# system is not used on the basis kernel. If updates are required +# in the basis kernel ordinary make commands (without M=...) must +# be used. +# +# The following are the only valid targets when building external +# modules. +# make M=dir clean Delete all automatically generated files +# make M=dir modules Make all modules in specified dir +# make M=dir Same as 'make M=dir modules' +# make M=dir modules_install +# Install the modules built in the module directory +# Assumes install directory is already created + +# We are always building modules +KBUILD_MODULES := 1 +PHONY += crmodverdir +crmodverdir: + $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* + +PHONY += $(objtree)/Module.symvers +$(objtree)/Module.symvers: + @test -e $(objtree)/Module.symvers || ( \ + echo; \ + echo " WARNING: Symbol version dump $(objtree)/Module.symvers"; \ + echo " is missing; modules will have no dependencies and modversions."; \ + echo ) + +module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) +PHONY += $(module-dirs) modules +$(module-dirs): crmodverdir $(objtree)/Module.symvers + $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) + +modules: $(module-dirs) + @echo ' Building modules, stage 2.'; + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + +PHONY += modules_install +modules_install: _emodinst_ _emodinst_post + +install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra) +PHONY += _emodinst_ +_emodinst_: + $(Q)mkdir -p $(MODLIB)/$(install-dir) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst + +# Run depmod only is we have System.map and depmod is executable +quiet_cmd_depmod = DEPMOD $(KERNELRELEASE) + cmd_depmod = if [ -r System.map -a -x $(DEPMOD) ]; then \ + $(DEPMOD) -ae -F System.map \ + $(if $(strip $(INSTALL_MOD_PATH)), \ + -b $(INSTALL_MOD_PATH) -r) \ + $(KERNELRELEASE); \ + fi + +PHONY += _emodinst_post +_emodinst_post: _emodinst_ + $(call cmd,depmod) + +clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD)) + +PHONY += $(clean-dirs) clean +$(clean-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) + +clean: rm-dirs := $(MODVERDIR) +clean: $(clean-dirs) + $(call cmd,rmdirs) + @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ + -type f -print | xargs rm -f + +help: + @echo ' Building external modules.' + @echo ' Syntax: make -C path/to/kernel/src M=$$PWD target' + @echo '' + @echo ' modules - default target, build the module(s)' + @echo ' modules_install - install the module' + @echo ' clean - remove generated files in module directory only' + @echo '' + +# Dummies... +PHONY += prepare scripts +prepare: ; +scripts: ; +endif # KBUILD_EXTMOD + +# Generate tags for editors +# --------------------------------------------------------------------------- + +#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set +#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file. +#Adding $(srctree) adds about 20M on i386 to the size of the output file! + +ifeq ($(src),$(obj)) +__srctree = +else +__srctree = $(srctree)/ +endif + +ifeq ($(ALLSOURCE_ARCHS),) +ifeq ($(ARCH),um) +ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH) +else +ALLINCLUDE_ARCHS := $(ARCH) +endif +else +#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behavour. +ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS) +endif + +ALLSOURCE_ARCHS := $(ARCH) + +define find-sources + ( find $(__srctree) $(RCS_FIND_IGNORE) \ + \( -name include -o -name arch \) -prune -o \ + -name $1 -print; \ + for ARCH in $(ALLSOURCE_ARCHS) ; do \ + find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \ + -name $1 -print; \ + done ; \ + find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \ + -name $1 -print; \ + find $(__srctree)include $(RCS_FIND_IGNORE) \ + \( -name config -o -name 'asm-*' \) -prune \ + -o -name $1 -print; \ + for ARCH in $(ALLINCLUDE_ARCHS) ; do \ + find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \ + -name $1 -print; \ + done ; \ + find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \ + -name $1 -print ) +endef + +define all-sources + $(call find-sources,'*.[chS]') +endef +define all-kconfigs + $(call find-sources,'Kconfig*') +endef +define all-defconfigs + $(call find-sources,'defconfig') +endef + +define xtags + if $1 --version 2>&1 | grep -iq exuberant; then \ + $(all-sources) | xargs $1 -a \ + -I __initdata,__exitdata,__acquires,__releases \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + --extra=+f --c-kinds=+px \ + --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \ + $(all-kconfigs) | xargs $1 -a \ + --langdef=kconfig \ + --language-force=kconfig \ + --regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \ + $(all-defconfigs) | xargs -r $1 -a \ + --langdef=dotconfig \ + --language-force=dotconfig \ + --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \ + elif $1 --version 2>&1 | grep -iq emacs; then \ + $(all-sources) | xargs $1 -a; \ + $(all-kconfigs) | xargs $1 -a \ + --regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \ + $(all-defconfigs) | xargs -r $1 -a \ + --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \ + else \ + $(all-sources) | xargs $1 -a; \ + fi +endef + +quiet_cmd_cscope-file = FILELST cscope.files + cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files + +quiet_cmd_cscope = MAKE cscope.out + cmd_cscope = cscope -b + +cscope: FORCE + $(call cmd,cscope-file) + $(call cmd,cscope) + +quiet_cmd_TAGS = MAKE $@ +define cmd_TAGS + rm -f $@; \ + $(call xtags,etags) +endef + +TAGS: FORCE + $(call cmd,TAGS) + +quiet_cmd_tags = MAKE $@ +define cmd_tags + rm -f $@; \ + $(call xtags,ctags) +endef + +tags: FORCE + $(call cmd,tags) + + +# Scripts to check various things for consistency +# --------------------------------------------------------------------------- + +includecheck: + find * $(RCS_FIND_IGNORE) \ + -name '*.[hcS]' -type f -print | sort \ + | xargs $(PERL) -w scripts/checkincludes.pl + +versioncheck: + find * $(RCS_FIND_IGNORE) \ + -name '*.[hcS]' -type f -print | sort \ + | xargs $(PERL) -w scripts/checkversion.pl + +namespacecheck: + $(PERL) $(srctree)/scripts/namespace.pl + +endif #ifeq ($(config-targets),1) +endif #ifeq ($(mixed-targets),1) + +PHONY += checkstack kernelrelease kernelversion + +# Use $(SUBARCH) here instead of $(ARCH) so that this works for UML. +# In the UML case, $(SUBARCH) is the name of the underlying +# architecture, while for all other arches, it is the same as $(ARCH). +checkstack: + $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \ + $(PERL) $(src)/scripts/checkstack.pl $(SUBARCH) + +kernelrelease: + $(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \ + $(error kernelrelease not valid - run 'make prepare' to update it)) +kernelversion: + @echo $(KERNELVERSION) + +# Single targets +# --------------------------------------------------------------------------- +# Single targets are compatible with: +# - build whith mixed source and output +# - build with separate output dir 'make O=...' +# - external modules +# +# target-dir => where to store outputfile +# build-dir => directory in kernel source tree to use + +ifeq ($(KBUILD_EXTMOD),) + build-dir = $(patsubst %/,%,$(dir $@)) + target-dir = $(dir $@) +else + zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@))) + build-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash)) + target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) +endif + +%.s: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.i: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.lst: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.s: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.symtypes: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) + +# Modules +/ %/: prepare scripts FORCE + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) +%.ko: prepare scripts FORCE + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) $(@:.ko=.o) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + +# FIXME Should go into a make.lib or something +# =========================================================================== + +quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs))) + cmd_rmdirs = rm -rf $(rm-dirs) + +quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))) + cmd_rmfiles = rm -f $(rm-files) + + +a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(AFLAGS_KERNEL) \ + $(NOSTDINC_FLAGS) $(CPPFLAGS) \ + $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o) + +quiet_cmd_as_o_S = AS $@ +cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< + +# read all saved command lines + +targets := $(wildcard $(sort $(targets))) +cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) + +ifneq ($(cmd_files),) + $(cmd_files): ; # Do not try to update included dependency files + include $(cmd_files) +endif + +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir +# Usage: +# $(Q)$(MAKE) $(clean)=dir +clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj + +endif # skip-makefile + +PHONY += FORCE +FORCE: + + +# Declare the contents of the .PHONY variable as phony. We keep that +# information in a variable se we can use it in if_changed and friends. +.PHONY: $(PHONY) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ce00c570..7b9750ee 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -22,8 +22,11 @@ config GENERIC_TIME default n config MMU - bool + bool "MMU-based Paged Memory Management Support" default y + help + Select if you want MMU-based virtualised addressing space + support by paged memory management. If unsure, say 'Y'. config EISA bool @@ -112,6 +115,8 @@ menu "System Type" choice prompt "ARM system type" default ARCH_VERSATILE + default ARCH_S3C2500 if !MMU + default ARCH_ATMEL if !MMU config ARCH_AAEC2000 bool "Agilent AAEC-2000 based" @@ -237,6 +242,13 @@ config ARCH_IXP2000 help Support for Intel's IXP2400/2800 (XScale) family of processors. +config ARCH_KS8695 + bool "Kendin-Micrel KS8695" + help + The Kendin-Micrel KS8695 "Centaur" family is an ARM920 based + System-On-Chip device. It is commonly used on small routers and + other small scale embedded devices. + config ARCH_IXP23XX bool "IXP23XX-based" depends on MMU @@ -317,6 +329,90 @@ config ARCH_OMAP help Support for TI's OMAP platform (OMAP1 and OMAP2). +config ARCH_S5C7375 + bool "Samsung S5C7375" + depends !MMU + help + Samsung's S5C7375 16/32-bit SOC(ARM920T) for internal use. + It can be supported for memory management type MMU(Linux) and + + +config ARCH_S3C24A0 + bool "Samsung S3C24A0" + depends !MMU + help + Samsung's S3C24A0 media processor based on ARM926EJ core. + +config ARCH_S3C2500 + bool "Samsung S3C2500" + help + Samsung's S3C2500 SOC(ARM940T). + +config ARCH_ATMEL + bool "Atmel AT91xxx" + depends on !MMU + help + The AT91xxx Series is a subset of the Atmel AT91 16/32-bit + microcontroller family, which is based on the ARM7TDMI + processor core. + refer + + You can also choose this architecture for The GDB/Armulator. + It emulates AT91F40, include ARM7TDMI core and timers/serial. + refer . + +config ARCH_S3C3410 + bool "Samsung S3C3410X" + depends on !MMU + help + Samsung's S3C3410X(KS17C40100) 16/32-bit RISC MCU + is a cost-effective and high-performance MCU solution for PDA and + general purpose application. The core is ARM7TDMI. + + refer . + +config ARCH_MOXART + bool "Moxa ART CPU" + depends on !MMU + help + Moxa's ART 16/32-bit RISC MCU + + refer . + +config ARCH_ESPD_4510B + bool "ESPD 4510B / Samsung S3C4510B" + depends on !MMU + help + ESPD 4510B evaluation board built on Samsung's + S3C4510B(KS32C50100) 16/32-bit RISC MCU + is a high performance network controller based + on the ARM7TDMI core. + + refer to + +config ARCH_S3C44B0 + bool "Samsung S3C44B0" + depends on !MMU + help + Samsung's S3C44B0X 16/32-bit SOC(ARM7TDMI) without coprocessor + +config ARCH_P2001 + bool "P2001" + depends on !MMU + help + The LPEC P2001 evaluation board has an P2001 processor from + MAZ Brandenburg GmbH, which is based an ARM9TDMI processor core. + +config ARCH_LPC22xx + bool "Philips LPC22xx" + depends on !MMU + help + Philips LPC22xx series are based on ARM7TDMI-S core, + housed in LQFP144 packages, equipped with + 16/64KB on-chip RAM and up to 256KB of on-chip Flash, + operating at up to 60MHz together with + a wide range of peripherals and external bus options. + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -333,6 +429,8 @@ source "arch/arm/mach-iop33x/Kconfig" source "arch/arm/mach-ixp4xx/Kconfig" +source "arch/arm/mach-ks8695/Kconfig" + source "arch/arm/mach-ixp2000/Kconfig" source "arch/arm/mach-ixp23xx/Kconfig" @@ -357,6 +455,22 @@ source "arch/arm/mach-h720x/Kconfig" source "arch/arm/mach-versatile/Kconfig" +source "arch/arm/mach-atmel/Kconfig" + +source "arch/arm/mach-s3c3410/Kconfig" + +source "arch/arm/mach-s3c44b0x/Kconfig" + +source "arch/arm/mach-s5c7375/Kconfig" + +source "arch/arm/mach-espd_4510b/Kconfig" + +source "arch/arm/mach-lpc22xx/Kconfig" + +source "arch/arm/mach-s3c24a0/Kconfig" + +source "arch/arm/mach-p2001/Kconfig" + source "arch/arm/mach-aaec2000/Kconfig" source "arch/arm/mach-realview/Kconfig" @@ -365,6 +479,8 @@ source "arch/arm/mach-at91rm9200/Kconfig" source "arch/arm/mach-netx/Kconfig" +source "arch/arm/mach-moxart/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool @@ -417,7 +533,7 @@ config ISA_DMA_API bool config PCI - bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX + bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside @@ -627,7 +743,7 @@ config LEDS_CPU config ALIGNMENT_TRAP bool depends on CPU_CP15_MMU - default y if !ARCH_EBSA110 + default y if !ARCH_EBSA110 && !ARCH_S3C3410 && !ARCH_ATMEL && !ARCH_ESPD_4510B && !ARCH_MOXART help ARM processors cannot fetch/store information which is not naturally aligned on the bus, i.e., a 4 byte fetch must start at an @@ -684,6 +800,12 @@ config CMDLINE time by entering them here. As a minimum, you should specify the memory size and the root device (e.g., mem=64M root=/dev/nfs). +config CMDLINE_FORCE + bool "Force default kernel command string" + help + Set this to have arguments from the default kernel command string + override those passed by the boot loader. + config XIP_KERNEL bool "Kernel Execute-In-Place from ROM" depends on !ZBOOT_ROM @@ -714,9 +836,16 @@ config XIP_PHYS_ADDR be linked for and stored to. This address is dependent on your own flash usage. +config INITRD_MTD + bool "Use initrd as MTD RAM root filesystem" + depends on MTD_PLATRAM && !BLK_DEV_INITRD + help + Create an MTD RAM device at the memory range specified by the + initrd parameters, and mount this as the root filesystem. + endmenu -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP1 || ARCH_P2001) menu "CPU Frequency scaling" @@ -743,6 +872,13 @@ config CPU_FREQ_INTEGRATOR If in doubt, say Y. +config CPU_FREQ_P2001 + tristate 'P2001 cpufreq support' + depends on ARCH_P2001 && CPU_FREQ && CPU_FREQ_TABLE + default n + help + Compiles P2001 cpu frequency scaling module. + endmenu endif @@ -901,8 +1037,6 @@ source "drivers/char/Kconfig" source "drivers/i2c/Kconfig" -source "drivers/spi/Kconfig" - source "drivers/w1/Kconfig" source "drivers/hwmon/Kconfig" diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu index f0873767..ccf645c6 100644 --- a/arch/arm/Kconfig-nommu +++ b/arch/arm/Kconfig-nommu @@ -3,6 +3,15 @@ # Hyok S. Choi # +config PROCESSOR_ID + hex 'Hard processor ID' + default 0x00007700 + depends on !CPU_CP15 + help + Hard set the processor ID to this value. If the processor has no + CP15 register then the kernel cannot probe the processor ID, and + so hard setting the value is the only option. + config SET_MEM_PARAM bool "Set flash/sdram size and base addr" help @@ -25,14 +34,6 @@ config FLASH_SIZE hex 'FLASH Size' if SET_MEM_PARAM default 0x00400000 -config PROCESSOR_ID - hex - default 0x00007700 - depends on !CPU_CP15 - help - If processor has no CP15 register, this processor ID is - used instead of the auto-probing which utilizes the register. - config REMAP_VECTORS_TO_RAM bool 'Install vectors to the begining of RAM' if DRAM_BASE depends on DRAM_BASE diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index d22f38b9..53c7e059 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -7,7 +7,7 @@ source "lib/Kconfig.debug" # traces, you can get a slightly smaller kernel by setting this option to # n, but then RMK will have to kill you ;). config FRAME_POINTER - bool + bool "Enable frame pointer" default y help If you say N here, the resulting kernel will be slightly smaller and diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 6f4f8bf3..8e5a575f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -65,6 +65,8 @@ tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM946T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale @@ -111,6 +113,7 @@ endif machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_IXP2000) := ixp2000 machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx + machine-$(CONFIG_ARCH_KS8695) := ks8695 machine-$(CONFIG_ARCH_OMAP1) := omap1 machine-$(CONFIG_ARCH_OMAP2) := omap2 incdir-$(CONFIG_ARCH_OMAP) := omap @@ -120,6 +123,27 @@ endif machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_H720X) := h720x machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 + machine-$(CONFIG_ARCH_ATMEL) := atmel +textaddr-$(CONFIG_ARCH_ATMEL) := 0x01000000 + machine-$(CONFIG_ARCH_ESPD_4510B) := espd_4510b +textaddr-$(CONFIG_ARCH_ESPD_4510B) := 0x00008000 + machine-$(CONFIG_ARCH_S3C3410) := s3c3410 +textaddr-$(CONFIG_ARCH_S3C3410) := 0x01020000 + machine-$(CONFIG_ARCH_MOXART) := moxart +textaddr-$(CONFIG_ARCH_MOXART) := 0x00080000 +textofs-$(CONFIG_ARCH_MOXART) := 0x00080000 + machine-$(CONFIG_ARCH_S3C44B0) := s3c44b0x +textaddr-$(CONFIG_ARCH_S3C44B0) := 0x0c008000 + machine-$(CONFIG_ARCH_S5C7375) := s5c7375 +textaddr-$(CONFIG_ARCH_S5C7375) := 0x00008000 + machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 +ifeq ($(CONFIG_MMU),) +textaddr-$(CONFIG_ARCH_S3C24A0) := 0x10008000 +endif + machine-$(CONFIG_ARCH_P2001) := p2001 +textaddr-$(CONFIG_ARCH_P2001) := 0x40100000 + machine-$(CONFIG_ARCH_LPC22xx) := lpc22xx +textaddr-$(CONFIG_ARCH_LPC22xx) := 0x81008000 machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_AT91) := at91rm9200 machine-$(CONFIG_ARCH_EP93XX) := ep93xx @@ -179,7 +203,8 @@ else KBUILD_IMAGE := zImage endif -all: $(KBUILD_IMAGE) +#all: $(KBUILD_IMAGE) +all: uCImage boot := arch/arm/boot @@ -209,6 +234,12 @@ bzImage: zImage zImage Image xipImage bootpImage uImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ +uCImage: vmlinux linux.bin + +linux.bin: vmlinux FORCE + @$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux $@ + @echo ' Kernel: $@ is ready' + zinstall install: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index ec9c400c..a101f394 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -13,14 +13,18 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh -ifneq ($(MACHINE),) -include $(srctree)/$(MACHINE)/Makefile.boot -endif +#ifneq ($(MACHINE),) +#include $(srctree)/$(MACHINE)/Makefile.boot +#endif # Note: the following conditions must always be true: # ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET) # PARAMS_PHYS must be within 4MB of ZRELADDR # INITRD_PHYS must be in RAM + +zreladdr-$(CONFIG_ARCH_MOXART) := 0x00080000 +initrd_phys-$(CONFIG_ARCH_MOXART) := 0x00000000 + ZRELADDR := $(zreladdr-y) PARAMS_PHYS := $(params_phys-y) INITRD_PHYS := $(initrd_phys-y) diff --git a/arch/arm/boot/bootp/bootp.lds b/arch/arm/boot/bootp/bootp.lds index 8e3d81ce..c39ff79f 100644 --- a/arch/arm/boot/bootp/bootp.lds +++ b/arch/arm/boot/bootp/bootp.lds @@ -2,12 +2,17 @@ * linux/arch/arm/boot/bootp/bootp.lds * * Copyright (C) 2000-2002 Russell King + * Modified by Hyok S. Choi, 2004 * * 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. */ + +#ifdef CONFIG_MMU OUTPUT_ARCH(arm) +#endif + ENTRY(_start) SECTIONS { diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index adddc713..3288a026 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -38,6 +38,17 @@ ifeq ($(CONFIG_ARCH_SA1100),y) OBJS += head-sa1100.o endif +ifeq ($(CONFIG_ARCH_S3C44B0),y) +HEAD = head-s3c44b0.o +endif + +ifeq ($(CONFIG_ARCH_P2001),y) +HEAD = head-p2001.o +endif + +ifeq ($(CONFIG_ARCH_ESPD_4510B),y) +HEAD = head-espd_4510b.o +endif ifeq ($(CONFIG_CPU_XSCALE),y) OBJS += head-xscale.o endif @@ -46,6 +57,10 @@ ifeq ($(CONFIG_PXA_SHARPSL),y) OBJS += head-sharpsl.o endif +ifeq ($(CONFIG_ARCH_KS8695),y) +OBJS += head-ks8695.o +endif + ifeq ($(CONFIG_ARCH_AT91RM9200),y) OBJS += head-at91rm9200.o endif @@ -71,7 +86,7 @@ ZTEXTADDR := 0 ZBSSADDR := ALIGN(4) endif -SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ +SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ targets := vmlinux vmlinux.lds piggy.gz piggy.o $(FONT) \ head.o misc.o $(OBJS) diff --git a/arch/arm/boot/compressed/head-espd_4510b.S b/arch/arm/boot/compressed/head-espd_4510b.S new file mode 100644 index 00000000..19e8dd2c --- /dev/null +++ b/arch/arm/boot/compressed/head-espd_4510b.S @@ -0,0 +1,447 @@ +/* + * linux/arch/arm/boot/compressed/head-espd_4510b.S + * + * Copyright (C) 1996-2002 Russell King + * Copyright (C) 2004 Hyok S. Choi (MPU support) + * + * 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 + +/* + * Debugging stuff + * + * Note that these macros must not contain any code which is not + * 100% relocatable. Any attempt to do so will result in a crash. + * Please select one of the following when turning on debugging. + */ +#ifdef DEBUG +#if defined(CONFIG_DEBUG_ICEDCC) + .macro loadsp, rb + .endm + .macro writeb, rb + mcr p14, 0, \rb, c0, c1, 0 + .endm +#else +#error no serial architecture defined +#endif +#endif + + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start +#ifdef DEBUG + kputc #'\n' + kphex r6, 8 /* processor id */ + kputc #':' + kphex r7, 8 /* architecture id */ + kputc #':' + mrc p15, 0, r0, c1, c0 + kphex r0, 8 /* control reg */ + kputc #'\n' + kphex r5, 8 /* decompressed kernel start */ + kputc #'-' + kphex r8, 8 /* decompressed kernel end */ + kputc #'>' + kphex r4, 8 /* kernel execution address */ + kputc #'\n' +#endif + .endm + + .macro debug_reloc_end +#ifdef DEBUG + kphex r5, 8 /* end of kernel */ + kputc #'\n' + mov r0, r4 + bl memdump /* dump 256 bytes at start of kernel */ +#endif + .endm + + .section ".start", #alloc, #execinstr +/* + * sort out different calling conventions + */ + .align +start: + .type start,#function + .rept 8 + mov r0, r0 + .endr + + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address + .word _edata @ zImage end address +1: mov r7, r1 @ save architecture ID + mov r8, #0 @ save r0 + +#ifndef __ARM_ARCH_2__ + /* + * Booting from Angel - need to enter SVC mode and disable + * FIQs/IRQs (numeric definitions from angel arm.h source). + * We only do this if we were in user mode on entry. + */ + mrs r2, cpsr @ get current mode + tst r2, #3 @ not user? + bne not_angel + mov r0, #0x17 @ angel_SWIreason_EnterSVC + swi 0x123456 @ angel_SWI_ARM +not_angel: + mrs r2, cpsr @ turn off interrupts to + orr r2, r2, #0xc0 @ prevent angel from running + msr cpsr_c, r2 +#else + teqp pc, #0x0c000003 @ turn off interrupts +#endif + + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? + */ + + /* + * some architecture specific code can be inserted + * by the linker here, but it should preserve r7 and r8. + */ + + .text + adr r0, LC0 + ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} + subs r0, r0, r1 @ calculate the delta offset + + @ if delta is zero, we are + beq not_relocated @ running at the address we + @ were linked at. + + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 + add r6, r6, r0 + add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 + add sp, sp, r0 + + /* + * Relocate all entries in the GOT table. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + add r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif + +not_relocated: mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 + cmp r2, r3 + blo 1b + + /* + * Reset Ethernet BDMA (before cache on) + */ + ldr r3, =0x8000 @ BDMA reset + ldr r2, =0x3FF9000 @ BDMATXCON + str r3, [r2] + ldr r2, =0x3FF9004 @ BDMARXCON + str r3, [r2] + + /* + * The C runtime environment should now be setup + * sufficiently. Turn the cache on, set up some + * pointers, and start decompressing. + */ + bl cache_on + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + +/* + * Check to see if we will overwrite ourselves. + * r4 = final kernel address + * r5 = start of this image + * r2 = end of malloc space (and therefore this image) + * We basically want: + * r4 >= r2 -> OK + * r4 + image length <= r5 -> OK + */ + cmp r4, r2 + bhs wont_overwrite + add r0, r4, #4096*1024 @ 4MB largest kernel size + cmp r0, r5 + bls wont_overwrite + + mov r5, r2 @ decompress after malloc space + mov r0, r5 + mov r3, r7 + bl decompress_kernel + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length +/* + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + ldr r3, LC1 + add r3, r2, r3 +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 + blo 1b + + bl cache_clean_flush + add pc, r5, r0 @ call relocation code + +/* + * We're not in danger of overwriting ourselves. Do this the simple way. + * + * r4 = kernel execution address + * r7 = architecture ID + */ +wont_overwrite: mov r0, r4 + mov r3, r7 + bl decompress_kernel + b call_kernel + + .type LC0, #object +LC0: .word LC0 @ r1 + .word __bss_start @ r2 + .word _end @ r3 + .word zreladdr @ r4 + .word _start @ r5 + .word _got_start @ r6 + .word _got_end @ ip + .word user_stack+4096 @ sp +LC1: .word reloc_end - reloc_start + .size LC0, . - LC0 + +/* + * Turn on the cache. We need to setup some page tables so that we + * can have both the I and D caches on. + * + * We place the page tables 16k down from the kernel execution address, + * and we hope that nothing else is using it. If we're using it, we + * will go pop! + * + * On entry, + * r4 = kernel execution address + * r6 = processor ID + * r7 = architecture number + * r8 = run-time address of "start" + * On exit, + * r1, r2, r3, r8, r9, r12 corrupted + * This routine must preserve: + * r4, r5, r6, r7 + */ + .align 5 +cache_on: + /* cache/write buffer on */ + ldr r0, =0x3FF0000 @ SYSCFG + ldr r2, [r0] + orr r2, r2, #6 @ Cache and write buffer + str r2, [r0] + mov pc, lr + +/* + * All code following this line is relocatable. It is relocated by + * the above code to the end of the decompressed kernel image and + * executed there. During this time, we have no stacks. + * + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + .align 5 +reloc_start: add r8, r5, r0 + debug_reloc_start + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} + .endr + + cmp r5, r8 + blo 1b + debug_reloc_end + +call_kernel: bl cache_clean_flush + bl cache_off + mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + + +/* + * Turn off the Cache and MMU. ARMv3 does not support + * reading the control register, but ARMv4 does. + * + * On entry, r6 = processor ID + * On exit, r0, r1, r2, r3, r12 corrupted + * This routine must preserve: r4, r6, r7 + */ + .align 5 +cache_off: + /* cache/write buffer off */ + ldr r0, =0x3FF0000 @ SYSCFG + ldr r2, [r0] + bic r2, r2, #6 @ Cache and write buffer + str r2, [r0] + mov pc, lr +/* + * Clean and flush the cache to maintain consistency. + * + * On entry, + * r6 = processor ID + * On exit, + * r1, r2, r3, r11, r12 corrupted + * This routine must preserve: + * r0, r4, r5, r6, r7 + */ + .align 5 +cache_clean_flush: +/* + * cf. Ch-5 of S3C4510 user's manual for + * "Cache flush operation" + * To clear Tag RAM area. + */ + ldr r1, =0x11000000 + mov r2, #0 + mov r12, #256 +cache_flush_loop: + str r2, [r1], #4 + subs r12, r12, #1 + bne cache_flush_loop + mov pc, lr + +/* + * Various debugging routines for printing hex characters and + * memory, which again must be relocatable. + */ +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 + mov r0, #0 + loadsp r3 + b 2b + +memdump: mov r12, r0 + mov r10, lr + mov r11, #0 +2: mov r0, r11, lsl #2 + add r0, r0, r12 + mov r1, #8 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +#endif + +reloc_end: + + .align + .section ".stack", "w" +user_stack: .space 4096 diff --git a/arch/arm/boot/compressed/head-ks8695.S b/arch/arm/boot/compressed/head-ks8695.S new file mode 100644 index 00000000..2038de47 --- /dev/null +++ b/arch/arm/boot/compressed/head-ks8695.S @@ -0,0 +1,5 @@ +#include + + .section ".start", "ax" + mov r7, #(MACH_TYPE_KS8695 & 0xff) + orr r7, r7, #(MACH_TYPE_KS8695 & 0xff00) diff --git a/arch/arm/boot/compressed/head-p2001.S b/arch/arm/boot/compressed/head-p2001.S new file mode 100644 index 00000000..0926f9ae --- /dev/null +++ b/arch/arm/boot/compressed/head-p2001.S @@ -0,0 +1,382 @@ +/* + * linux/arch/armnommu/boot/compressed/head-p2001.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 + +/* + * Debugging stuff + * + * Note that these macros must not contain any code which is not + * 100% relocatable. Any attempt to do so will result in a crash. + * Please select one of the following when turning on debugging. + */ +#ifdef DEBUG + .macro loadsp, rb + mov \rb, #0x00140000 @ Adr_UART_OLD_BASE + .endm + + .macro writeb, rb + str \rb, [r3, #0x00] @ REL_Adr_Uart_TX1 + .endm +#endif + + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start +#ifdef DEBUG + kputc #'\n' + kphex r6, 8 /* processor id */ + kputc #':' + kphex r7, 8 /* architecture id */ + kputc #'\n' + kphex r5, 8 /* decompressed kernel start */ + kputc #'-' + kphex r8, 8 /* decompressed kernel end */ + kputc #'>' + kphex r4, 8 /* kernel execution address */ + kputc #'\n' +#endif + .endm + + .macro debug_reloc_end +#ifdef DEBUG + kphex r5, 8 /* end of kernel */ + kputc #'\n' + mov r0, r4 + bl memdump /* dump 256 bytes at start of kernel */ +#endif + .endm + + + .section ".start", #alloc, #execinstr +/* + * sort out different calling conventions + */ + .align +start: + .type start,#function + .rept 8 + mov r0, r0 + .endr + + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address + .word _edata @ zImage end address +1: mov r7, r1 @ save architecture ID + mov r8, #0 @ save r0 + + /* + * Booting from P2001 - need to enter SVC mode and disable + * FIQs/IRQs (numeric definitions from angel arm.h source). + * We only do this if we were in user mode on entry. + */ + mrs r2, cpsr @ get current mode + orr r2, r2, #0xc0 @ turn off interrupts + msr cpsr_c, r2 + + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? + */ + + /* + * some architecture specific code can be inserted + * by the linker here, but it should preserve r7 and r8. + */ + + .text + adr r0, LC0 + ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} + subs r0, r0, r1 @ calculate the delta offset + + @ if delta is zero, we're + beq not_relocated @ running at the address we + @ were linked at. + + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 + add r6, r6, r0 + add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 + add sp, sp, r0 + + /* + * Relocate all entries in the GOT table. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + add r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif + +not_relocated: mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 + cmp r2, r3 + blo 1b + + /* + * The C runtime environment should now be setup + * sufficiently. Set up some pointers, and start decompressing. + */ + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + +/* + * Check to see if we will overwrite ourselves. + * r4 = final kernel address + * r5 = start of this image + * r2 = end of malloc space (and therefore this image) + * We basically want: + * r4 >= r2 -> OK + * r4 + image length <= r5 -> OK + */ + cmp r4, r2 + bhs wont_overwrite + add r0, r4, #4096*1024 @ 4MB largest kernel size + cmp r0, r5 + bls wont_overwrite + + mov r5, r2 @ decompress after malloc space + mov r0, r5 + mov r3, r7 + bl decompress_kernel + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length +/* + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + ldr r3, LC1 + add r3, r2, r3 +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 + blo 1b + + add pc, r5, r0 @ call relocation code + +/* + * We're not in danger of overwriting ourselves. Do this the simple way. + * + * r4 = kernel execution address + * r7 = architecture ID + */ +wont_overwrite: mov r0, r4 + mov r3, r7 + bl decompress_kernel + b call_kernel + + .type LC0, #object +LC0: .word LC0 @ r1 + .word __bss_start @ r2 + .word _end @ r3 + .word _load_addr @ r4 + .word _start @ r5 + .word _got_start @ r6 + .word _got_end @ ip + .word user_stack+4096 @ sp +LC1: .word reloc_end - reloc_start + .size LC0, . - LC0 + +/* + * Initialise the page tables, turning on the cacheable and bufferable + * bits for the RAM area only. + */ + mov r0, r3 + mov r8, r0, lsr #18 + mov r8, r8, lsl #18 @ start of RAM + add r9, r8, #0x10000000 @ a reasonable RAM size + mov r1, #0x12 + orr r1, r1, #3 << 10 + add r2, r3, #16384 +1: cmp r1, r8 @ if virt > start of RAM + orrhs r1, r1, #0x0c @ set cacheable, bufferable + cmp r1, r9 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping + add r1, r1, #1048576 + teq r0, r2 + bne 1b +/* + * If ever we are running from Flash, then we surely want the cache + * to be enabled also for our execution instance... We map 2MB of it + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ + mov r1, #0x1e + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 + add r0, r3, r2, lsl #2 + str r1, [r0], #4 + add r1, r1, #1048576 + str r1, [r0] + mov pc, lr + +/* + * All code following this line is relocatable. It is relocated by + * the above code to the end of the decompressed kernel image and + * executed there. During this time, we have no stacks. + * + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + .align 5 +reloc_start: add r8, r5, r0 + debug_reloc_start + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} + .endr + + cmp r5, r8 + blo 1b + debug_reloc_end + +call_kernel: mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + +/* + * Various debugging routines for printing hex characters and + * memory, which again must be relocatable. + */ +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 + mov r0, #0 + loadsp r3 + b 2b + +memdump: mov r12, r0 + mov r10, lr + mov r11, #0 +2: mov r0, r11, lsl #2 + add r0, r0, r12 + mov r1, #8 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +#endif + +reloc_end: + + .align + .section ".stack", "w" +user_stack: .space 4096 diff --git a/arch/arm/boot/compressed/head-s3c44b0.S b/arch/arm/boot/compressed/head-s3c44b0.S new file mode 100644 index 00000000..e4137c80 --- /dev/null +++ b/arch/arm/boot/compressed/head-s3c44b0.S @@ -0,0 +1,371 @@ +/* + * linux/arch/armnommu/boot/compressed/head.S + * + * Copyright (C) 1996-2002 Russell King + * Copyright (C) 2004 Hyok S. Choi (MPU support) + * + * 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 +#include + +/* + * Debugging stuff + * + * Note that these macros must not contain any code which is not + * 100% relocatable. Any attempt to do so will result in a crash. + * Please select one of the following when turning on debugging. + */ + + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start +#ifdef DEBUG + kputc #'\n' + kphex r6, 8 /* processor id */ + kputc #':' + kphex r7, 8 /* architecture id */ + kputc #':' + mrc p15, 0, r0, c1, c0 + kphex r0, 8 /* control reg */ + kputc #'\n' + kphex r5, 8 /* decompressed kernel start */ + kputc #'-' + kphex r8, 8 /* decompressed kernel end */ + kputc #'>' + kphex r4, 8 /* kernel execution address */ + kputc #'\n' +#endif + .endm + + .macro debug_reloc_end +#ifdef DEBUG + kphex r5, 8 /* end of kernel */ + kputc #'\n' + mov r0, r4 + bl memdump /* dump 256 bytes at start of kernel */ +#endif + .endm + + .section ".start", #alloc, #execinstr +/* + * sort out different calling conventions + */ + .align +start: + .type start,#function + .rept 8 + mov r0, r0 + .endr + + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address + .word _edata @ zImage end address +1: mov r7, r1 @ save architecture ID + mov r8, #0 @ save r0 + +#ifndef __ARM_ARCH_2__ + /* + * Booting from Angel - need to enter SVC mode and disable + * FIQs/IRQs (numeric definitions from angel arm.h source). + * We only do this if we were in user mode on entry. + */ + mrs r2, cpsr @ get current mode + tst r2, #3 @ not user? + bne not_angel + mov r0, #0x17 @ angel_SWIreason_EnterSVC + swi 0x123456 @ angel_SWI_ARM +not_angel: + mrs r2, cpsr @ turn off interrupts to + orr r2, r2, #0xc0 @ prevent angel from running + msr cpsr_c, r2 +#else + teqp pc, #0x0c000003 @ turn off interrupts +#endif + + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? + */ + + /* + * some architecture specific code can be inserted + * by the linker here, but it should preserve r7 and r8. + */ + + .text + adr r0, LC0 + ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} + subs r0, r0, r1 @ calculate the delta offset + + @ if delta is zero, we're + beq not_relocated @ running at the address we + @ were linked at. + + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 + add r6, r6, r0 + add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 + add sp, sp, r0 + + /* + * Relocate all entries in the GOT table. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + add r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif + +not_relocated: mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 + cmp r2, r3 + blo 1b + + /* + * The C runtime environment should now be setup + * sufficiently. Turn the cache on, set up some + * pointers, and start decompressing. + */ + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + +/* + * Check to see if we will overwrite ourselves. + * r4 = final kernel address + * r5 = start of this image + * r2 = end of malloc space (and therefore this image) + * We basically want: + * r4 >= r2 -> OK + * r4 + image length <= r5 -> OK + */ + cmp r4, r2 + bhs wont_overwrite + add r0, r4, #4096*1024 @ 4MB largest kernel size + cmp r0, r5 + bls wont_overwrite + + mov r5, r2 @ decompress after malloc space + mov r0, r5 + mov r3, r7 + bl decompress_kernel + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length +/* + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + ldr r3, LC1 + add r3, r2, r3 +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 + blo 1b + + add pc, r5, r0 @ call relocation code + +/* + * We're not in danger of overwriting ourselves. Do this the simple way. + * + * r4 = kernel execution address + * r7 = architecture ID + */ +wont_overwrite: mov r0, r4 + mov r3, r7 + bl decompress_kernel + b call_kernel + + .type LC0, #object +LC0: .word LC0 @ r1 + .word __bss_start @ r2 + .word _end @ r3 + .word _load_addr @ r4 + .word _start @ r5 + .word _got_start @ r6 + .word _got_end @ ip + .word user_stack+4096 @ sp +LC1: .word reloc_end - reloc_start + .size LC0, . - LC0 + +/* + * All code following this line is relocatable. It is relocated by + * the above code to the end of the decompressed kernel image and + * executed there. During this time, we have no stacks. + * + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + .align 5 +reloc_start: add r8, r5, r0 + debug_reloc_start + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} + .endr + + cmp r5, r8 + blo 1b + debug_reloc_end + +call_kernel: + +#ifdef CONFIG_ARCH_S3C44B0 + ldr r2, S3C44B0_PROCESSOR_TYPE + str r2, [r6] + ldr r2, S3C44B0_MACH_TYPE + str r2, [r9] + mov fp, #0 + b 1f +S3C44B0_PROCESSOR_TYPE: + .long 0x44b07700 +S3C44B0_MACH_TYPE: + .long MACH_TYPE_S3C44B0 + +1: +#endif + + mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + +/* + * Various debugging routines for printing hex characters and + * memory, which again must be relocatable. + */ +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 + mov r0, #0 + loadsp r3 + b 2b + +memdump: mov r12, r0 + mov r10, lr + mov r11, #0 +2: mov r0, r11, lsl #2 + add r0, r0, r12 + mov r1, #8 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +#endif + +reloc_end: + + .align + .section ".stack", "w" +user_stack: .space 4096 diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S index 73c5d9e0..0dda8aeb 100644 --- a/arch/arm/boot/compressed/head-xscale.S +++ b/arch/arm/boot/compressed/head-xscale.S @@ -41,6 +41,105 @@ __XScale_start: mov r7, #MACH_TYPE_COTULLA_IDP #endif +#ifdef CONFIG_ARCH_IQ80310 + /* + * Crank the CPU up to 733MHz + */ + mov r1, #9 + mcr p14, 0, r1, c6, c0, 0 + + /* + * Disable ECC error notification + * At some point, we should add an ECC handler to Linux + */ + mov r1, #0x1500 + mov r0, #0x4 + str r0, [r1, #0x34] + + mov r7, #MACH_TYPE_IQ80310 +#endif + +#ifdef CONFIG_ARCH_IXDP425 + mov r7, #MACH_TYPE_IXDP425 +#endif + +#ifdef CONFIG_MACH_IXDP465 + mov r7, #MACH_TYPE_IXDP465 & 0xff + orr r7, r7, #MACH_TYPE_IXDP465 & 0xff00 +#endif + +#ifdef CONFIG_MACH_IXDPG425 + mov r7, #MACH_TYPE_IXDPG425 & 0xff + orr r7, r7, #MACH_TYPE_IXDPG425 & 0xff00 +#endif + +#ifdef CONFIG_ARCH_PRPMC1100 + mov r7, #(MACH_TYPE_PRPMC1100 & 0xff) + orr r7, r7, #(MACH_TYPE_PRPMC1100 & 0xff00) +#endif + +#ifdef CONFIG_ARCH_ADI_COYOTE + # Set machine ID into r7 (Coyote ID > 255 hence needs + # two instructions to build the ID safely). + mov r7, #MACH_TYPE_ADI_COYOTE & 0xff + orr r7, r7, #MACH_TYPE_ADI_COYOTE & 0xff00 +#endif + +#ifdef CONFIG_ARCH_SE4000 + mov r7, #MACH_TYPE_SE4000 & 0xff + orr r7, r7, #MACH_TYPE_SE4000 & 0xff00 +#endif + +#ifdef CONFIG_MACH_ESS710 + mov r7, #MACH_TYPE_ESS710 & 0xff + orr r7, r7, #MACH_TYPE_ESS710 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG720 + mov r7, #MACH_TYPE_SG720 & 0xff + orr r7, r7, #MACH_TYPE_SG720 & 0xff00 +#endif + +#ifdef CONFIG_MACH_MONTEJADE + mov r7, #MACH_TYPE_MONTEJADE & 0xff + orr r7, r7, #MACH_TYPE_MONTEJADE & 0xff00 +#endif + +#ifdef CONFIG_MACH_IVPN + mov r7, #MACH_TYPE_IVPN & 0xff + orr r7, r7, #MACH_TYPE_IVPN & 0xff00 +#endif + +#ifdef CONFIG_MACH_SE5100 + mov r7, #MACH_TYPE_SE5100 & 0xff + orr r7, r7, #MACH_TYPE_SE5100 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG560 + mov r7, #MACH_TYPE_SG560 & 0xff + orr r7, r7, #MACH_TYPE_SG560 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG565 + mov r7, #MACH_TYPE_SG565 & 0xff + orr r7, r7, #MACH_TYPE_SG565 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG580 + mov r7, #MACH_TYPE_SG580 & 0xff + orr r7, r7, #MACH_TYPE_SG580 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG590 + mov r7, #MACH_TYPE_SG590 & 0xff + orr r7, r7, #MACH_TYPE_SG590 & 0xff00 +#endif + +#ifdef CONFIG_MACH_SG640 + mov r7, #MACH_TYPE_SG640 & 0xff + orr r7, r7, #MACH_TYPE_SG640 & 0xff00 +#endif + #ifdef CONFIG_MACH_GTWX5715 mov r7, #(MACH_TYPE_GTWX5715 & 0xff) orr r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 2568d311..75505d8a 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -2,12 +2,12 @@ * linux/arch/arm/boot/compressed/head.S * * Copyright (C) 1996-2002 Russell King - * Copyright (C) 2004 Hyok S. Choi (MPU support) * * 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 #include /* @@ -18,50 +18,107 @@ * Please select one of the following when turning on debugging. */ #ifdef DEBUG - -#if defined(CONFIG_DEBUG_ICEDCC) - -#ifdef CONFIG_CPU_V6 +#if defined(CONFIG_DEBUG_DC21285_PORT) .macro loadsp, rb + mov \rb, #0x42000000 .endm - .macro writeb, ch, rb - mcr p14, 0, \ch, c0, c5, 0 + .macro writeb, rb + str \rb, [r3, #0x160] .endm -#else +#elif defined(CONFIG_DEBUG_ICEDCC) .macro loadsp, rb .endm - .macro writeb, ch, rb - mcr p14, 0, \ch, c0, c1, 0 + .macro writeb, rb + mcr p14, 0, \rb, c0, c1, 0 .endm -#endif - -#else - -#include - - .macro writeb, ch, rb - senduart \ch, \rb +#elif defined(CONFIG_FOOTBRIDGE) + .macro loadsp, rb + mov \rb, #0x7c000000 .endm - -#if defined(CONFIG_ARCH_SA1100) + .macro writeb, rb + strb \rb, [r3, #0x3f8] + .endm +#elif defined(CONFIG_ARCH_RPC) + .macro loadsp, rb + mov \rb, #0x03000000 + orr \rb, \rb, #0x00010000 + .endm + .macro writeb, rb + strb \rb, [r3, #0x3f8 << 2] + .endm +#elif defined(CONFIG_ARCH_INTEGRATOR) + .macro loadsp, rb + mov \rb, #0x16000000 + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm +#elif defined(CONFIG_ARCH_PXA) /* Xscale-type */ + .macro loadsp, rb + mov \rb, #0x40000000 + orr \rb, \rb, #0x00100000 + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm +#elif defined(CONFIG_ARCH_SA1100) .macro loadsp, rb mov \rb, #0x80000000 @ physical base address -#ifdef CONFIG_DEBUG_LL_SER3 +# if defined(CONFIG_DEBUG_LL_SER3) add \rb, \rb, #0x00050000 @ Ser3 -#else +# else add \rb, \rb, #0x00010000 @ Ser1 +# endif + .endm + .macro writeb, rb + str \rb, [r3, #0x14] @ UTDR + .endm +#elif defined(CONFIG_ARCH_IXP4XX) + .macro loadsp, rb + mov \rb, #0xc8000000 + .endm + .macro writeb, rb + str \rb, [r3, #0] +#elif defined(CONFIG_ARCH_IXP2000) + .macro loadsp, rb + mov \rb, #0xc0000000 + orr \rb, \rb, #0x00030000 + .endm + .macro writeb, rb + str \rb, [r3, #0] + .endm +#elif defined(CONFIG_ARCH_LH7A40X) + .macro loadsp, rb + ldr \rb, =0x80000700 @ UART2 UARTBASE + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm +#elif defined(CONFIG_ARCH_OMAP) + .macro loadsp, rb + mov \rb, #0xff000000 @ physical base address + add \rb, \rb, #0x00fb0000 +#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3) + add \rb, \rb, #0x00000800 +#endif +#ifdef CONFIG_OMAP_LL_DEBUG_UART3 + add \rb, \rb, #0x00009000 #endif .endm -#elif defined(CONFIG_ARCH_S3C2410) + .macro writeb, rb + strb \rb, [r3] + .endm +#elif defined(CONFIG_ARCH_IOP331) .macro loadsp, rb - mov \rb, #0x50000000 - add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT + mov \rb, #0xff000000 + orr \rb, \rb, #0x00ff0000 + orr \rb, \rb, #0x0000f700 @ location of the UART .endm -#else - .macro loadsp, rb - addruart \rb + .macro writeb, rb + str \rb, [r3, #0] .endm -#endif +#else +#error no serial architecture defined #endif #endif @@ -82,15 +139,13 @@ kphex r6, 8 /* processor id */ kputc #':' kphex r7, 8 /* architecture id */ -#ifdef CONFIG_CPU_CP15 kputc #':' mrc p15, 0, r0, c1, c0 kphex r0, 8 /* control reg */ -#endif kputc #'\n' kphex r5, 8 /* decompressed kernel start */ kputc #'-' - kphex r9, 8 /* decompressed kernel end */ + kphex r8, 8 /* decompressed kernel end */ kputc #'>' kphex r4, 8 /* kernel execution address */ kputc #'\n' @@ -122,7 +177,14 @@ start: .word start @ absolute load/run zImage address .word _edata @ zImage end address 1: mov r7, r1 @ save architecture ID - mov r8, r2 @ save atags pointer + mov r8, #0 @ save r0 +// following mask by Victor Yu. 06-08-2005 +#if 0 + mov r2, #0xc8000000 + mov r3, #'a' + str r3, [r2] +#endif +// above mask by Victor Yu. 06-08-2005 #ifndef __ARM_ARCH_2__ /* @@ -150,7 +212,7 @@ not_angel: /* * some architecture specific code can be inserted - * by the linker here, but it should preserve r7, r8, and r9. + * by the linker here, but it should preserve r7 and r8. */ .text @@ -237,8 +299,7 @@ not_relocated: mov r0, #0 */ cmp r4, r2 bhs wont_overwrite - sub r3, sp, r5 @ > compressed kernel size - add r0, r4, r3, lsl #2 @ allow for 4x expansion + add r0, r4, #4096*1024 @ 4MB largest kernel size cmp r0, r5 bls wont_overwrite @@ -256,17 +317,16 @@ not_relocated: mov r0, #0 * r5 = decompressed kernel start * r6 = processor ID * r7 = architecture ID - * r8 = atags pointer - * r9-r14 = corrupted + * r8-r14 = unused */ add r1, r5, r0 @ end of decompressed kernel adr r2, reloc_start ldr r3, LC1 add r3, r2, r3 -1: ldmia r2!, {r9 - r14} @ copy relocation code - stmia r1!, {r9 - r14} - ldmia r2!, {r9 - r14} - stmia r1!, {r9 - r14} +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} cmp r2, r3 blo 1b @@ -288,7 +348,7 @@ wont_overwrite: mov r0, r4 LC0: .word LC0 @ r1 .word __bss_start @ r2 .word _end @ r3 - .word zreladdr @ r4 + .word _load_addr @ r4 .word _start @ r5 .word _got_start @ r6 .word _got_end @ ip @@ -316,73 +376,16 @@ params: ldr r0, =params_phys * r4 = kernel execution address * r6 = processor ID * r7 = architecture number - * r8 = atags pointer - * r9 = run-time address of "start" (???) + * r8 = run-time address of "start" * On exit, - * r1, r2, r3, r9, r10, r12 corrupted + * r1, r2, r3, r8, r9, r12 corrupted * This routine must preserve: - * r4, r5, r6, r7, r8 + * r4, r5, r6, r7 */ .align 5 cache_on: mov r3, #8 @ cache_on function b call_cache_fn -/* - * Initialize the highest priority protection region, PR7 - * to cover all 32bit address and cacheable and bufferable. - */ -__armv4_mpu_cache_on: - mov r0, #0x3f @ 4G, the whole - mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting - mcr p15, 0, r0, c6, c7, 1 - - mov r0, #0x80 @ PR7 - mcr p15, 0, r0, c2, c0, 0 @ D-cache on - mcr p15, 0, r0, c2, c0, 1 @ I-cache on - mcr p15, 0, r0, c3, c0, 0 @ write-buffer on - - mov r0, #0xc000 - mcr p15, 0, r0, c5, c0, 1 @ I-access permission - mcr p15, 0, r0, c5, c0, 0 @ D-access permission - - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer - mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache - mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache - mrc p15, 0, r0, c1, c0, 0 @ read control reg - @ ...I .... ..D. WC.M - orr r0, r0, #0x002d @ .... .... ..1. 11.1 - orr r0, r0, #0x1000 @ ...1 .... .... .... - - mcr p15, 0, r0, c1, c0, 0 @ write control reg - - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache - mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache - mov pc, lr - -__armv3_mpu_cache_on: - mov r0, #0x3f @ 4G, the whole - mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting - - mov r0, #0x80 @ PR7 - mcr p15, 0, r0, c2, c0, 0 @ cache on - mcr p15, 0, r0, c3, c0, 0 @ write-buffer on - - mov r0, #0xc000 - mcr p15, 0, r0, c5, c0, 0 @ access permission - - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 - mrc p15, 0, r0, c1, c0, 0 @ read control reg - @ .... .... .... WC.M - orr r0, r0, #0x000d @ .... .... .... 11.1 - mov r0, #0 - mcr p15, 0, r0, c1, c0, 0 @ write control reg - - mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 - mov pc, lr - __setup_mmu: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f00 @@ -391,15 +394,15 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size * bits for the RAM area only. */ mov r0, r3 - mov r9, r0, lsr #18 - mov r9, r9, lsl #18 @ start of RAM - add r10, r9, #0x10000000 @ a reasonable RAM size + mov r8, r0, lsr #18 + mov r8, r8, lsl #18 @ start of RAM + add r9, r8, #0x10000000 @ a reasonable RAM size mov r1, #0x12 orr r1, r1, #3 << 10 add r2, r3, #16384 -1: cmp r1, r9 @ if virt > start of RAM +1: cmp r1, r8 @ if virt > start of RAM orrhs r1, r1, #0x0c @ set cacheable, bufferable - cmp r1, r10 @ if virt > end of RAM + cmp r1, r9 @ if virt > end of RAM bichs r1, r1, #0x0c @ clear cacheable, bufferable str r1, [r0], #4 @ 1:1 mapping add r1, r1, #1048576 @@ -421,7 +424,7 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size str r1, [r0] mov pc, lr -__armv4_mmu_cache_on: +__armv4_cache_on: mov r12, lr bl __setup_mmu mov r0, #0 @@ -430,35 +433,40 @@ __armv4_mmu_cache_on: mrc p15, 0, r0, c1, c0, 0 @ read control reg orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement orr r0, r0, #0x0030 - bl __common_mmu_cache_on + bl __common_cache_on mov r0, #0 mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs mov pc, r12 -__arm6_mmu_cache_on: +__arm6_cache_on: mov r12, lr bl __setup_mmu mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 mov r0, #0x30 - bl __common_mmu_cache_on + bl __common_cache_on mov r0, #0 mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 mov pc, r12 -__common_mmu_cache_on: +__common_cache_on: #ifndef DEBUG orr r0, r0, #0x000d @ Write buffer, mmu #endif mov r1, #-1 mcr p15, 0, r3, c2, c0, 0 @ load page table pointer mcr p15, 0, r1, c3, c0, 0 @ load domain access control - b 1f - .align 5 @ cache line aligned -1: mcr p15, 0, r0, c1, c0, 0 @ load control register - mrc p15, 0, r0, c1, c0, 0 @ and read it back to - sub pc, lr, r0, lsr #32 @ properly flush pipeline + mcr p15, 0, r0, c1, c0, 0 @ load control register +// following add by Victor Yu. 06-08-2005 +#if 1 +#ifdef CONFIG_ARCH_MOXART + mov r0, r0 + mov r0, r0 +#endif +#endif +// above add by Victor Yu. 06-08-2005 + mov pc, lr /* * All code following this line is relocatable. It is relocated by @@ -471,28 +479,26 @@ __common_mmu_cache_on: * r5 = decompressed kernel start * r6 = processor ID * r7 = architecture ID - * r8 = atags pointer - * r9-r14 = corrupted + * r8-r14 = unused */ .align 5 -reloc_start: add r9, r5, r0 +reloc_start: add r8, r5, r0 debug_reloc_start mov r1, r4 1: .rept 4 - ldmia r5!, {r0, r2, r3, r10 - r14} @ relocate kernel - stmia r1!, {r0, r2, r3, r10 - r14} + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} .endr - cmp r5, r9 + cmp r5, r8 blo 1b debug_reloc_end call_kernel: bl cache_clean_flush bl cache_off - mov r0, #0 @ must be zero + mov r0, #0 mov r1, r7 @ restore architecture number - mov r2, r8 @ restore atags pointer mov pc, r4 @ call kernel /* @@ -510,11 +516,7 @@ call_kernel: bl cache_clean_flush */ call_cache_fn: adr r12, proc_types -#ifdef CONFIG_CPU_CP15 mrc p15, 0, r6, c0, c0 @ get processor ID -#else - ldr r6, =CONFIG_PROCESSOR_ID -#endif 1: ldr r1, [r12, #0] @ get value ldr r2, [r12, #4] @ get mask eor r1, r1, r6 @ (real ^ match) @@ -541,12 +543,12 @@ call_cache_fn: adr r12, proc_types proc_types: .word 0x41560600 @ ARM6/610 .word 0xffffffe0 - b __arm6_mmu_cache_off @ works, but slow - b __arm6_mmu_cache_off + b __arm6_cache_off @ works, but slow + b __arm6_cache_off mov pc, lr -@ b __arm6_mmu_cache_on @ untested -@ b __arm6_mmu_cache_off -@ b __armv3_mmu_cache_flush +@ b __arm6_cache_on @ untested +@ b __arm6_cache_off +@ b __armv3_cache_flush .word 0x00000000 @ old ARM ID .word 0x0000f000 @@ -556,28 +558,16 @@ proc_types: .word 0x41007000 @ ARM7/710 .word 0xfff8fe00 - b __arm7_mmu_cache_off - b __arm7_mmu_cache_off + b __arm7_cache_off + b __arm7_cache_off mov pc, lr .word 0x41807200 @ ARM720T (writethrough) .word 0xffffff00 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off + b __armv4_cache_on + b __armv4_cache_off mov pc, lr - .word 0x41007400 @ ARM74x - .word 0xff00ff00 - b __armv3_mpu_cache_on - b __armv3_mpu_cache_off - b __armv3_mpu_cache_flush - - .word 0x41009400 @ ARM94x - .word 0xff00ff00 - b __armv4_mpu_cache_on - b __armv4_mpu_cache_off - b __armv4_mpu_cache_flush - .word 0x00007000 @ ARM7 IDs .word 0x0000f000 mov pc, lr @@ -588,41 +578,53 @@ proc_types: .word 0x4401a100 @ sa110 / sa1100 .word 0xffffffe0 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv4_mmu_cache_flush + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush .word 0x6901b110 @ sa1110 .word 0xfffffff0 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv4_mmu_cache_flush + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush @ These match on the architecture ID .word 0x00020000 @ ARMv4T .word 0x000f0000 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv4_mmu_cache_flush + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + +// following add by Victor Yu. 06-08-2005 +#if 1 +#ifdef CONFIG_ARCH_MOXART + .word 0x66015261 + .word 0xff01fff1 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush +#endif +#endif +// above add by Victor Yu. 06-08-2005 .word 0x00050000 @ ARMv5TE .word 0x000f0000 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv4_mmu_cache_flush + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush .word 0x00060000 @ ARMv5TEJ .word 0x000f0000 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv4_mmu_cache_flush + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush - .word 0x0007b000 @ ARMv6 - .word 0x0007f000 - b __armv4_mmu_cache_on - b __armv4_mmu_cache_off - b __armv6_mmu_cache_flush + .word 0x00070000 @ ARMv6 + .word 0x000f0000 + b __armv4_cache_on + b __armv4_cache_off + b __armv6_cache_flush .word 0 @ unrecognised type .word 0 @@ -644,42 +646,32 @@ proc_types: cache_off: mov r3, #12 @ cache_off function b call_cache_fn -__armv4_mpu_cache_off: - mrc p15, 0, r0, c1, c0 - bic r0, r0, #0x000d - mcr p15, 0, r0, c1, c0 @ turn MPU and cache off - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer - mcr p15, 0, r0, c7, c6, 0 @ flush D-Cache - mcr p15, 0, r0, c7, c5, 0 @ flush I-Cache - mov pc, lr - -__armv3_mpu_cache_off: - mrc p15, 0, r0, c1, c0 - bic r0, r0, #0x000d - mcr p15, 0, r0, c1, c0, 0 @ turn MPU and cache off - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 - mov pc, lr - -__armv4_mmu_cache_off: +__armv4_cache_off: mrc p15, 0, r0, c1, c0 bic r0, r0, #0x000d mcr p15, 0, r0, c1, c0 @ turn MMU and cache off mov r0, #0 mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4 mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4 +// following add by Victor Yu. 06-08-2005 +#if 1 +#ifdef CONFIG_ARCH_MOXART + mov r0, r0 + mov r0, r0 +#endif +#endif +// above add by Victor Yu. 06-08-2005 mov pc, lr -__arm6_mmu_cache_off: +__arm6_cache_off: mov r0, #0x00000030 @ ARM6 control reg. - b __armv3_mmu_cache_off + b __armv3_cache_off -__arm7_mmu_cache_off: +__arm7_cache_off: mov r0, #0x00000070 @ ARM7 control reg. - b __armv3_mmu_cache_off + b __armv3_cache_off -__armv3_mmu_cache_off: +__armv3_cache_off: mcr p15, 0, r0, c1, c0, 0 @ turn MMU and cache off mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 @@ -701,25 +693,7 @@ cache_clean_flush: mov r3, #16 b call_cache_fn -__armv4_mpu_cache_flush: - mov r2, #1 - mov r3, #0 - mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache - mov r1, #7 << 5 @ 8 segments -1: orr r3, r1, #63 << 26 @ 64 entries -2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 5 - bcs 1b @ segments 7 to 0 - - teq r2, #0 - mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - - -__armv6_mmu_cache_flush: +__armv6_cache_flush: mov r1, #0 mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D mcr p15, 0, r1, c7, c5, 0 @ invalidate I+BTB @@ -727,7 +701,7 @@ __armv6_mmu_cache_flush: mcr p15, 0, r1, c7, c10, 4 @ drain WB mov pc, lr -__armv4_mmu_cache_flush: +__armv4_cache_flush: mov r2, #64*1024 @ default: 32K dcache size (*2) mov r11, #32 @ default: 32 byte line size mrc p15, 0, r3, c0, c0, 1 @ read cache type @@ -744,6 +718,14 @@ __armv4_mmu_cache_flush: mov r11, #8 mov r11, r11, lsl r3 @ cache line size in bytes no_cache_id: +// following add by Victor Yu. 06-08-2005 +#if 1 +#ifdef CONFIG_ARCH_MOXART + mov r1, #0 + mcr p15, 0, r1, c7, c10, 0 @ clean D cache +#endif +#endif +// above add by Victor Yu. 06-08-2005 bic r1, pc, #63 @ align to longest cache line add r2, r1, r2 1: ldr r3, [r1], r11 @ s/w flush D cache @@ -755,8 +737,7 @@ no_cache_id: mcr p15, 0, r1, c7, c10, 4 @ drain WB mov pc, lr -__armv3_mmu_cache_flush: -__armv3_mpu_cache_flush: +__armv3_cache_flush: mov r1, #0 mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr @@ -788,7 +769,7 @@ puts: loadsp r3 1: ldrb r2, [r0], #1 teq r2, #0 moveq pc, lr -2: writeb r2, r3 +2: writeb r2 mov r1, #0x00020000 3: subs r1, r1, #1 bne 3b diff --git a/arch/arm/boot/compressed/head.S-bak-06072007 b/arch/arm/boot/compressed/head.S-bak-06072007 new file mode 100644 index 00000000..0d8cf75e --- /dev/null +++ b/arch/arm/boot/compressed/head.S-bak-06072007 @@ -0,0 +1,851 @@ +/* + * linux/arch/arm/boot/compressed/head.S + * + * Copyright (C) 1996-2002 Russell King + * Copyright (C) 2004 Hyok S. Choi (MPU support) + * + * 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 + +/* + * Debugging stuff + * + * Note that these macros must not contain any code which is not + * 100% relocatable. Any attempt to do so will result in a crash. + * Please select one of the following when turning on debugging. + */ +#ifdef DEBUG + +#if defined(CONFIG_DEBUG_ICEDCC) + +#ifdef CONFIG_CPU_V6 + .macro loadsp, rb + .endm + .macro writeb, ch, rb + mcr p14, 0, \ch, c0, c5, 0 + .endm +#else + .macro loadsp, rb + .endm + .macro writeb, ch, rb + mcr p14, 0, \ch, c0, c1, 0 + .endm +#endif + +#else + +#include + + .macro writeb, ch, rb + senduart \ch, \rb + .endm + +#if defined(CONFIG_ARCH_SA1100) + .macro loadsp, rb + mov \rb, #0x80000000 @ physical base address +#ifdef CONFIG_DEBUG_LL_SER3 + add \rb, \rb, #0x00050000 @ Ser3 +#else + add \rb, \rb, #0x00010000 @ Ser1 +#endif + .endm +#elif defined(CONFIG_ARCH_S3C2410) + .macro loadsp, rb + mov \rb, #0x50000000 + add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT + .endm +#else + .macro loadsp, rb + addruart \rb + .endm +#endif +#endif +#endif + + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start +#ifdef DEBUG + kputc #'\n' + kphex r6, 8 /* processor id */ + kputc #':' + kphex r7, 8 /* architecture id */ +#ifdef CONFIG_CPU_CP15 + kputc #':' + mrc p15, 0, r0, c1, c0 + kphex r0, 8 /* control reg */ +#endif + kputc #'\n' + kphex r5, 8 /* decompressed kernel start */ + kputc #'-' + kphex r9, 8 /* decompressed kernel end */ + kputc #'>' + kphex r4, 8 /* kernel execution address */ + kputc #'\n' +#endif + .endm + + .macro debug_reloc_end +#ifdef DEBUG + kphex r5, 8 /* end of kernel */ + kputc #'\n' + mov r0, r4 + bl memdump /* dump 256 bytes at start of kernel */ +#endif + .endm + + .section ".start", #alloc, #execinstr +/* + * sort out different calling conventions + */ + .align +start: + .type start,#function + .rept 8 + mov r0, r0 + .endr + + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address + .word _edata @ zImage end address +1: mov r7, r1 @ save architecture ID + mov r8, r2 @ save atags pointer + +#ifndef __ARM_ARCH_2__ + /* + * Booting from Angel - need to enter SVC mode and disable + * FIQs/IRQs (numeric definitions from angel arm.h source). + * We only do this if we were in user mode on entry. + */ + mrs r2, cpsr @ get current mode + tst r2, #3 @ not user? + bne not_angel + mov r0, #0x17 @ angel_SWIreason_EnterSVC + swi 0x123456 @ angel_SWI_ARM +not_angel: + mrs r2, cpsr @ turn off interrupts to + orr r2, r2, #0xc0 @ prevent angel from running + msr cpsr_c, r2 +#else + teqp pc, #0x0c000003 @ turn off interrupts +#endif + + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? + */ + + /* + * some architecture specific code can be inserted + * by the linker here, but it should preserve r7, r8, and r9. + */ + + .text + adr r0, LC0 + ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} + subs r0, r0, r1 @ calculate the delta offset + + @ if delta is zero, we are + beq not_relocated @ running at the address we + @ were linked at. + + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 + add r6, r6, r0 + add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 + add sp, sp, r0 + + /* + * Relocate all entries in the GOT table. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + add r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif + +not_relocated: mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 + cmp r2, r3 + blo 1b + + /* + * The C runtime environment should now be setup + * sufficiently. Turn the cache on, set up some + * pointers, and start decompressing. + */ + bl cache_on + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + +/* + * Check to see if we will overwrite ourselves. + * r4 = final kernel address + * r5 = start of this image + * r2 = end of malloc space (and therefore this image) + * We basically want: + * r4 >= r2 -> OK + * r4 + image length <= r5 -> OK + */ + cmp r4, r2 + bhs wont_overwrite + sub r3, sp, r5 @ > compressed kernel size + add r0, r4, r3, lsl #2 @ allow for 4x expansion + cmp r0, r5 + bls wont_overwrite + + mov r5, r2 @ decompress after malloc space + mov r0, r5 + mov r3, r7 + bl decompress_kernel + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length +/* + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8 = atags pointer + * r9-r14 = corrupted + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + ldr r3, LC1 + add r3, r2, r3 +1: ldmia r2!, {r9 - r14} @ copy relocation code + stmia r1!, {r9 - r14} + ldmia r2!, {r9 - r14} + stmia r1!, {r9 - r14} + cmp r2, r3 + blo 1b + + bl cache_clean_flush + add pc, r5, r0 @ call relocation code + +/* + * We're not in danger of overwriting ourselves. Do this the simple way. + * + * r4 = kernel execution address + * r7 = architecture ID + */ +wont_overwrite: mov r0, r4 + mov r3, r7 + bl decompress_kernel + b call_kernel + + .type LC0, #object +LC0: .word LC0 @ r1 + .word __bss_start @ r2 + .word _end @ r3 + .word zreladdr @ r4 + .word _start @ r5 + .word _got_start @ r6 + .word _got_end @ ip + .word user_stack+4096 @ sp +LC1: .word reloc_end - reloc_start + .size LC0, . - LC0 + +#ifdef CONFIG_ARCH_RPC + .globl params +params: ldr r0, =params_phys + mov pc, lr + .ltorg + .align +#endif + +/* + * Turn on the cache. We need to setup some page tables so that we + * can have both the I and D caches on. + * + * We place the page tables 16k down from the kernel execution address, + * and we hope that nothing else is using it. If we're using it, we + * will go pop! + * + * On entry, + * r4 = kernel execution address + * r6 = processor ID + * r7 = architecture number + * r8 = atags pointer + * r9 = run-time address of "start" (???) + * On exit, + * r1, r2, r3, r9, r10, r12 corrupted + * This routine must preserve: + * r4, r5, r6, r7, r8 + */ + .align 5 +cache_on: mov r3, #8 @ cache_on function + b call_cache_fn + +/* + * Initialize the highest priority protection region, PR7 + * to cover all 32bit address and cacheable and bufferable. + */ +__armv4_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + mcr p15, 0, r0, c6, c7, 1 + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ D-cache on + mcr p15, 0, r0, c2, c0, 1 @ I-cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 1 @ I-access permission + mcr p15, 0, r0, c5, c0, 0 @ D-access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ ...I .... ..D. WC.M + orr r0, r0, #0x002d @ .... .... ..1. 11.1 + orr r0, r0, #0x1000 @ ...1 .... .... .... + + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mov pc, lr + +__armv3_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 0 @ access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ .... .... .... WC.M + orr r0, r0, #0x000d @ .... .... .... 11.1 + mov r0, #0 + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + +__setup_mmu: sub r3, r4, #16384 @ Page directory size + bic r3, r3, #0xff @ Align the pointer + bic r3, r3, #0x3f00 +/* + * Initialise the page tables, turning on the cacheable and bufferable + * bits for the RAM area only. + */ + mov r0, r3 + mov r9, r0, lsr #18 + mov r9, r9, lsl #18 @ start of RAM + add r10, r9, #0x10000000 @ a reasonable RAM size + mov r1, #0x12 + orr r1, r1, #3 << 10 + add r2, r3, #16384 +1: cmp r1, r9 @ if virt > start of RAM + orrhs r1, r1, #0x0c @ set cacheable, bufferable + cmp r1, r10 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping + add r1, r1, #1048576 + teq r0, r2 + bne 1b +/* + * If ever we are running from Flash, then we surely want the cache + * to be enabled also for our execution instance... We map 2MB of it + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ + mov r1, #0x1e + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 + add r0, r3, r2, lsl #2 + str r1, [r0], #4 + add r1, r1, #1048576 + str r1, [r0] + mov pc, lr + +__armv4_mmu_cache_on: + mov r12, lr + bl __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mrc p15, 0, r0, c1, c0, 0 @ read control reg + orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement + orr r0, r0, #0x0030 + bl __common_mmu_cache_on + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mov pc, r12 + +__arm6_mmu_cache_on: + mov r12, lr + bl __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 + mov r0, #0x30 + bl __common_mmu_cache_on + mov r0, #0 + mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 + mov pc, r12 + +__common_mmu_cache_on: +#ifndef DEBUG + orr r0, r0, #0x000d @ Write buffer, mmu +#endif + mov r1, #-1 + mcr p15, 0, r3, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c3, c0, 0 @ load domain access control + b 1f + .align 5 @ cache line aligned +1: mcr p15, 0, r0, c1, c0, 0 @ load control register + mrc p15, 0, r0, c1, c0, 0 @ and read it back to + sub pc, lr, r0, lsr #32 @ properly flush pipeline + +/* + * All code following this line is relocatable. It is relocated by + * the above code to the end of the decompressed kernel image and + * executed there. During this time, we have no stacks. + * + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8 = atags pointer + * r9-r14 = corrupted + */ + .align 5 +reloc_start: add r9, r5, r0 + debug_reloc_start + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r0, r2, r3, r10 - r14} @ relocate kernel + stmia r1!, {r0, r2, r3, r10 - r14} + .endr + + cmp r5, r9 + blo 1b + debug_reloc_end + +call_kernel: bl cache_clean_flush + bl cache_off + mov r0, #0 @ must be zero + mov r1, r7 @ restore architecture number + mov r2, r8 @ restore atags pointer + mov pc, r4 @ call kernel + +/* + * Here follow the relocatable cache support functions for the + * various processors. This is a generic hook for locating an + * entry and jumping to an instruction at the specified offset + * from the start of the block. Please note this is all position + * independent code. + * + * r1 = corrupted + * r2 = corrupted + * r3 = block offset + * r6 = corrupted + * r12 = corrupted + */ + +call_cache_fn: adr r12, proc_types +#ifdef CONFIG_CPU_CP15 + mrc p15, 0, r6, c0, c0 @ get processor ID +#else + ldr r6, =CONFIG_PROCESSOR_ID +#endif +1: ldr r1, [r12, #0] @ get value + ldr r2, [r12, #4] @ get mask + eor r1, r1, r6 @ (real ^ match) + tst r1, r2 @ & mask + addeq pc, r12, r3 @ call cache function + add r12, r12, #4*5 + b 1b + +/* + * Table for cache operations. This is basically: + * - CPU ID match + * - CPU ID mask + * - 'cache on' method instruction + * - 'cache off' method instruction + * - 'cache flush' method instruction + * + * We match an entry using: ((real_id ^ match) & mask) == 0 + * + * Writethrough caches generally only need 'on' and 'off' + * methods. Writeback caches _must_ have the flush method + * defined. + */ + .type proc_types,#object +proc_types: + .word 0x41560600 @ ARM6/610 + .word 0xffffffe0 + b __arm6_mmu_cache_off @ works, but slow + b __arm6_mmu_cache_off + mov pc, lr +@ b __arm6_mmu_cache_on @ untested +@ b __arm6_mmu_cache_off +@ b __armv3_mmu_cache_flush + + .word 0x00000000 @ old ARM ID + .word 0x0000f000 + mov pc, lr + mov pc, lr + mov pc, lr + + .word 0x41007000 @ ARM7/710 + .word 0xfff8fe00 + b __arm7_mmu_cache_off + b __arm7_mmu_cache_off + mov pc, lr + + .word 0x41807200 @ ARM720T (writethrough) + .word 0xffffff00 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + mov pc, lr + .word 0x41007400 @ ARM74x + .word 0xff00ff00 + b __armv3_mpu_cache_on + b __armv3_mpu_cache_off + b __armv3_mpu_cache_flush + + .word 0x41009400 @ ARM94x + .word 0xff00ff00 + b __armv4_mpu_cache_on + b __armv4_mpu_cache_off + b __armv4_mpu_cache_flush + + .word 0x41007400 @ ARM74x + .word 0xff00ff00 + b __armv3_mpu_cache_on + b __armv3_mpu_cache_off + b __armv3_mpu_cache_flush + + .word 0x41009400 @ ARM94x + .word 0xff00ff00 + b __armv4_mpu_cache_on + b __armv4_mpu_cache_off + b __armv4_mpu_cache_flush + + .word 0x00007000 @ ARM7 IDs + .word 0x0000f000 + mov pc, lr + mov pc, lr + mov pc, lr + + @ Everything from here on will be the new ID system. + + .word 0x4401a100 @ sa110 / sa1100 + .word 0xffffffe0 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + + .word 0x6901b110 @ sa1110 + .word 0xfffffff0 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + + @ These match on the architecture ID + + .word 0x00020000 @ ARMv4T + .word 0x000f0000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + + .word 0x00050000 @ ARMv5TE + .word 0x000f0000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + + .word 0x00060000 @ ARMv5TEJ + .word 0x000f0000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv4_mmu_cache_flush + + .word 0x0007b000 @ ARMv6 + .word 0x0007f000 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv6_mmu_cache_flush + + .word 0 @ unrecognised type + .word 0 + mov pc, lr + mov pc, lr + mov pc, lr + + .size proc_types, . - proc_types + +/* + * Turn off the Cache and MMU. ARMv3 does not support + * reading the control register, but ARMv4 does. + * + * On entry, r6 = processor ID + * On exit, r0, r1, r2, r3, r12 corrupted + * This routine must preserve: r4, r6, r7 + */ + .align 5 +cache_off: mov r3, #12 @ cache_off function + b call_cache_fn + +__armv4_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c6, 0 @ flush D-Cache + mcr p15, 0, r0, c7, c5, 0 @ flush I-Cache + mov pc, lr + +__armv3_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0, 0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + +__armv4_mmu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MMU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4 + mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4 + mov pc, lr + +__arm6_mmu_cache_off: + mov r0, #0x00000030 @ ARM6 control reg. + b __armv3_mmu_cache_off + +__arm7_mmu_cache_off: + mov r0, #0x00000070 @ ARM7 control reg. + b __armv3_mmu_cache_off + +__armv3_mmu_cache_off: + mcr p15, 0, r0, c1, c0, 0 @ turn MMU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 + mov pc, lr + +/* + * Clean and flush the cache to maintain consistency. + * + * On entry, + * r6 = processor ID + * On exit, + * r1, r2, r3, r11, r12 corrupted + * This routine must preserve: + * r0, r4, r5, r6, r7 + */ + .align 5 +cache_clean_flush: + mov r3, #16 + b call_cache_fn + +__armv4_mpu_cache_flush: + mov r2, #1 + mov r3, #0 + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache + mov r1, #7 << 5 @ 8 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 + + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + + +__armv6_mmu_cache_flush: + mov r1, #0 + mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D + mcr p15, 0, r1, c7, c5, 0 @ invalidate I+BTB + mcr p15, 0, r1, c7, c15, 0 @ clean+invalidate unified + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +__armv4_mmu_cache_flush: + mov r2, #64*1024 @ default: 32K dcache size (*2) + mov r11, #32 @ default: 32 byte line size + mrc p15, 0, r3, c0, c0, 1 @ read cache type + teq r3, r6 @ cache ID register present? + beq no_cache_id + mov r1, r3, lsr #18 + and r1, r1, #7 + mov r2, #1024 + mov r2, r2, lsl r1 @ base dcache size *2 + tst r3, #1 << 14 @ test M bit + addne r2, r2, r2, lsr #1 @ +1/2 size if M == 1 + mov r3, r3, lsr #12 + and r3, r3, #3 + mov r11, #8 + mov r11, r11, lsl r3 @ cache line size in bytes +no_cache_id: + bic r1, pc, #63 @ align to longest cache line + add r2, r1, r2 +1: ldr r3, [r1], r11 @ s/w flush D cache + teq r1, r2 + bne 1b + + mcr p15, 0, r1, c7, c5, 0 @ flush I cache + mcr p15, 0, r1, c7, c6, 0 @ flush D cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +__armv3_mmu_cache_flush: +__armv3_mpu_cache_flush: + mov r1, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + +/* + * Various debugging routines for printing hex characters and + * memory, which again must be relocatable. + */ +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2, r3 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 + mov r0, #0 + loadsp r3 + b 2b + +memdump: mov r12, r0 + mov r10, lr + mov r11, #0 +2: mov r0, r11, lsl #2 + add r0, r0, r12 + mov r1, #8 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +#endif + +reloc_end: + + .align + .section ".stack", "w" +user_stack: .space 4096 diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 283891c7..5fed2b04 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -24,7 +24,9 @@ unsigned int __machine_arch_type; #define putstr printf #else +#if 0 // mask by Victor Yu. 06-08-2007 static void putstr(const char *ptr); +#endif #include #include @@ -69,6 +71,7 @@ static void icedcc_putc(int ch) #define flush() do { } while (0) #endif +#if 0 // mask by Vitor Yu. 06-08-2007 static void putstr(const char *ptr) { char c; @@ -81,6 +84,7 @@ static void putstr(const char *ptr) flush(); } +#endif #endif diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index d5f72010..102bc86b 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -564,6 +564,22 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->skpcr_mask = info->skpcr_mask; memmove(dev->irq, info->irq, sizeof(dev->irq)); + /* + * If the parent device has a DMA mask associated with it, + * propagate it down to the children. + */ + if (sachip->dev->dma_mask) { + dev->dma_mask = *sachip->dev->dma_mask; + dev->dev.dma_mask = &dev->dma_mask; + + if (dev->dma_mask != 0xffffffffUL) { + ret = dmabounce_register_dev(&dev->dev, 1024, 4096); + if (ret) { + printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); + } + } + } + ret = request_resource(parent, &dev->res); if (ret) { printk("SA1111: failed to allocate resource for %s\n", diff --git a/arch/arm/configs/EM1220_defconfig b/arch/arm/configs/EM1220_defconfig new file mode 100644 index 00000000..5974bede --- /dev/null +++ b/arch/arm/configs/EM1220_defconfig @@ -0,0 +1,980 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-uc1 +# Fri Mar 9 07:10:01 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_MMU is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0x00000000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="MoXaRt" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +CONFIG_ARCH_MOXART=y +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +# CONFIG_ARCH_LPC22xx is not set +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# MOXART Options +# +CONFIG_SYS_CLK=48000000 +CONFIG_UART_CLK=14745600 +CONFIG_LARGE_ALLOCS=y +# CONFIG_ARCH_UC7110 is not set +# CONFIG_ARCH_UC7112 is not set +# CONFIG_ARCH_EM1240 is not set +# CONFIG_ARCH_EM1240_IVTC is not set +CONFIG_ARCH_EM1220=y +# CONFIG_ARCH_EM1220_DLIN is not set +# CONFIG_ARCH_W321_GL is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_ARM7TDMI is not set +# CONFIG_CPU_ARM9TDMI is not set +CONFIG_CPU_ARM922T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_CP15=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_MXU_ENABLE is not set +# CONFIG_CPU_HIGH_VECTOR is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +CONFIG_TLS_REG_EMUL=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x80000000 +CONFIG_FLASH_SIZE=0x01000000 + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,19200 root=/dev/mtdblock2 rootfstype=jffs2 rw" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPSEC_NAT_TRAVERSAL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_CT_ACCT=y +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +CONFIG_IP_NF_CT_PROTO_SCTP=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_IRC=y +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=y +CONFIG_IP_NF_AMANDA=y +# CONFIG_IP_NF_PPTP is not set +# CONFIG_IP_NF_H323 is not set +# CONFIG_IP_NF_SIP is not set +# CONFIG_IP_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_KLIPS is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_EPCS is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_UC7112 is not set +CONFIG_MTD_EM1220=y +# CONFIG_MTD_EM1220_DLIN is not set +# CONFIG_MTD_EM1240 is not set +# CONFIG_MTD_EM1240_IVTC is not set +# CONFIG_MTD_W321_GL is not set +# CONFIG_MTD_UC7110 is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_UCLINUX is not set +# CONFIG_MTD_SNAPGEARuC is not set +# CONFIG_MTD_M520x is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_AVNET5282 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4608 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MOXA_NET=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_OPEN_ETH is not set +# CONFIG_MTIP1000_ETH is not set +# CONFIG_DM9000 is not set +# CONFIG_NE2000 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UC71XX_GPIO=m +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +CONFIG_MOXA_SMARTIO=m +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_LEDMAN is not set +# CONFIG_SNAPDOG is not set +# CONFIG_FAST_TIMER is not set +CONFIG_RESETSWITCH=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DCC is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_UC7110WDT=y +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_M41T11M6 is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=m +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MMC_MOXART=m + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_DIRECTIO is not set +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Debug +# +# CONFIG_COREDUMP_PRINTK is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_PLIST=y diff --git a/arch/arm/configs/EM1240_defconfig b/arch/arm/configs/EM1240_defconfig new file mode 100644 index 00000000..0c7ff59c --- /dev/null +++ b/arch/arm/configs/EM1240_defconfig @@ -0,0 +1,920 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-uc1 +# Sat Mar 3 15:20:40 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_MMU is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0x00000000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="MoXaRt" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +CONFIG_ARCH_MOXART=y +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +# CONFIG_ARCH_LPC22xx is not set +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# MOXART Options +# +CONFIG_SYS_CLK=48000000 +CONFIG_UART_CLK=14745600 +CONFIG_LARGE_ALLOCS=y + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_ARM7TDMI is not set +# CONFIG_CPU_ARM9TDMI is not set +CONFIG_CPU_ARM922T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_CP15=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_MXU_ENABLE is not set +# CONFIG_CPU_HIGH_VECTOR is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +CONFIG_TLS_REG_EMUL=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x80000000 +CONFIG_FLASH_SIZE=0x01000000 + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,19200 root=/dev/mtdblock2 rootfstype=jffs2 rw" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPSEC_NAT_TRAVERSAL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_CT_ACCT=y +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +CONFIG_IP_NF_CT_PROTO_SCTP=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_IRC=y +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=y +CONFIG_IP_NF_AMANDA=y +# CONFIG_IP_NF_PPTP is not set +# CONFIG_IP_NF_H323 is not set +# CONFIG_IP_NF_SIP is not set +# CONFIG_IP_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_KLIPS is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_EPCS is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_UC7110LX=y +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_UCLINUX is not set +# CONFIG_MTD_SNAPGEARuC is not set +# CONFIG_MTD_M520x is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_AVNET5282 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4608 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MOXA_NET=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_OPEN_ETH is not set +# CONFIG_MTIP1000_ETH is not set +# CONFIG_DM9000 is not set +# CONFIG_NE2000 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UC71XX_GPIO=m +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +CONFIG_MOXA_SMARTIO=m +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_LEDMAN is not set +# CONFIG_SNAPDOG is not set +# CONFIG_FAST_TIMER is not set +CONFIG_RESETSWITCH=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DCC is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_UC7110WDT=y +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_M41T11M6 is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_DIRECTIO is not set +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Debug +# +# CONFIG_COREDUMP_PRINTK is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_PLIST=y diff --git a/arch/arm/configs/GDB_ARMulator_defconfig b/arch/arm/configs/GDB_ARMulator_defconfig new file mode 100644 index 00000000..6a9595c3 --- /dev/null +++ b/arch/arm/configs/GDB_ARMulator_defconfig @@ -0,0 +1,481 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:17:25 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +CONFIG_ARCH_ATMEL=y +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x01000000 +CONFIG_DRAM_SIZE=0x00400000 +CONFIG_FLASH_MEM_BASE=0x01400000 +CONFIG_FLASH_SIZE=0x00400000 +# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set + +# +# ATMEL Options +# +CONFIG_ARM_CLK=40000000 +CONFIG_SKIP_DUMP_CPU_INFO=y +CONFIG_MEM16_BASE=0x03000000 +CONFIG_MEM8_BASE=0x03000000 +CONFIG_IO16_BASE=0x02000000 +CONFIG_IO8_BASE=0x02000000 +CONFIG_CPU_AT91X40=y +# CONFIG_CPU_AT91X63 is not set +# CONFIG_ATMEL_DEBUG is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_CPU_32v4=y +CONFIG_CPU_CACHE_V4=y + +# +# Processor Features +# + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram initrd=0x01300000,768K keepinitrd" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=2048 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DCC is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_SYSFS is not set +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/configs/UC7110_defconfig b/arch/arm/configs/UC7110_defconfig new file mode 100644 index 00000000..8b9e7d39 --- /dev/null +++ b/arch/arm/configs/UC7110_defconfig @@ -0,0 +1,932 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-uc1 +# Thu Mar 15 07:24:13 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_MMU is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0x00000000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="MoXaRt" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +# CONFIG_BUG is not set +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +CONFIG_ARCH_MOXART=y +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +# CONFIG_ARCH_LPC22xx is not set +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# MOXART Options +# +CONFIG_SYS_CLK=48000000 +CONFIG_UART_CLK=14745600 +CONFIG_LARGE_ALLOCS=y +CONFIG_ARCH_UC7110=y +# CONFIG_ARCH_UC7112 is not set +# CONFIG_ARCH_EM1240 is not set +# CONFIG_ARCH_EM1240_IVTC is not set +# CONFIG_ARCH_EM1220 is not set +# CONFIG_ARCH_EM1220_DLIN is not set +# CONFIG_ARCH_W321_GL is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_ARM7TDMI is not set +# CONFIG_CPU_ARM9TDMI is not set +CONFIG_CPU_ARM922T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_NOMMU=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_CP15=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_MXU_ENABLE is not set +# CONFIG_CPU_HIGH_VECTOR is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +CONFIG_TLS_REG_EMUL=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x80000000 +CONFIG_FLASH_SIZE=0x01000000 + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,19200 root=/dev/mtdblock2 rootfstype=jffs2 rw" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPSEC_NAT_TRAVERSAL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_CT_ACCT=y +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +CONFIG_IP_NF_CT_PROTO_SCTP=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_IRC=y +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=y +CONFIG_IP_NF_AMANDA=y +# CONFIG_IP_NF_PPTP is not set +# CONFIG_IP_NF_H323 is not set +# CONFIG_IP_NF_SIP is not set +# CONFIG_IP_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_KLIPS is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_EPCS is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_UC7112 is not set +# CONFIG_MTD_EM1220 is not set +# CONFIG_MTD_EM1220_DLIN is not set +# CONFIG_MTD_EM1240 is not set +# CONFIG_MTD_EM1240_IVTC is not set +# CONFIG_MTD_W321_GL is not set +CONFIG_MTD_UC7110=y +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_UCLINUX is not set +# CONFIG_MTD_SNAPGEARuC is not set +# CONFIG_MTD_M520x is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_AVNET5282 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=8 +CONFIG_BLK_DEV_RAM_SIZE=4608 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MOXA_NET=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_OPEN_ETH is not set +# CONFIG_MTIP1000_ETH is not set +# CONFIG_DM9000 is not set +# CONFIG_NE2000 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UC71XX_GPIO=m +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +CONFIG_MOXA_SMARTIO=m +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_LEDMAN is not set +# CONFIG_SNAPDOG is not set +# CONFIG_FAST_TIMER is not set +CONFIG_RESETSWITCH=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DCC is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_UC7110WDT=y +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_M41T11M6 is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_DIRECTIO is not set +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Debug +# +# CONFIG_COREDUMP_PRINTK is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_PLIST=y diff --git a/arch/arm/configs/UC7112_defconfig b/arch/arm/configs/UC7112_defconfig new file mode 100644 index 00000000..08764a80 --- /dev/null +++ b/arch/arm/configs/UC7112_defconfig @@ -0,0 +1,978 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-uc1 +# Thu Mar 8 16:28:32 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_MMU is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_VECTORS_BASE=0x00000000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="MoXaRt" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +CONFIG_ARCH_MOXART=y +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +# CONFIG_ARCH_LPC22xx is not set +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# MOXART Options +# +CONFIG_SYS_CLK=48000000 +CONFIG_UART_CLK=14745600 +CONFIG_LARGE_ALLOCS=y +# CONFIG_ARCH_UC7110 is not set +CONFIG_ARCH_UC7112=y +# CONFIG_ARCH_EM1240 is not set +# CONFIG_ARCH_EM1240_IVTC is not set +# CONFIG_ARCH_EM1220 is not set +# CONFIG_ARCH_EM1220_DLIN is not set +# CONFIG_ARCH_W321_GL is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_ARM7TDMI is not set +# CONFIG_CPU_ARM9TDMI is not set +CONFIG_CPU_ARM922T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_CP15=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_MXU_ENABLE is not set +# CONFIG_CPU_HIGH_VECTOR is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +CONFIG_TLS_REG_EMUL=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x80000000 +CONFIG_FLASH_SIZE=0x00800000 + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,19200 root=/dev/mtdblock2 rootfstype=jffs2 rw" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPSEC_NAT_TRAVERSAL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_CT_ACCT=y +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +CONFIG_IP_NF_CT_PROTO_SCTP=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_IRC=y +# CONFIG_IP_NF_NETBIOS_NS is not set +CONFIG_IP_NF_TFTP=y +CONFIG_IP_NF_AMANDA=y +# CONFIG_IP_NF_PPTP is not set +# CONFIG_IP_NF_H323 is not set +# CONFIG_IP_NF_SIP is not set +# CONFIG_IP_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_KLIPS is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_EPCS is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_UC7112=y +# CONFIG_MTD_EM1220 is not set +# CONFIG_MTD_EM1220_DLIN is not set +# CONFIG_MTD_EM1240 is not set +# CONFIG_MTD_EM1240_IVTC is not set +# CONFIG_MTD_W321_GL is not set +# CONFIG_MTD_UC7110 is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_UCLINUX is not set +# CONFIG_MTD_SNAPGEARuC is not set +# CONFIG_MTD_M520x is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_AVNET5282 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4608 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MOXA_NET=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_OPEN_ETH is not set +# CONFIG_MTIP1000_ETH is not set +# CONFIG_DM9000 is not set +# CONFIG_NE2000 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_UC71XX_GPIO is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +CONFIG_MOXA_SMARTIO=m +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_LEDMAN is not set +# CONFIG_SNAPDOG is not set +# CONFIG_FAST_TIMER is not set +CONFIG_RESETSWITCH=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DCC is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_UC7110WDT=y +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_M41T11M6 is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=m +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MMC_MOXART=m + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_DIRECTIO is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +CONFIG_SOLARIS_X86_PARTITION=y +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Debug +# +# CONFIG_COREDUMP_PRINTK is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_PLIST=y diff --git a/arch/arm/configs/atmel_defconfig b/arch/arm/configs/atmel_defconfig new file mode 100644 index 00000000..6a9595c3 --- /dev/null +++ b/arch/arm/configs/atmel_defconfig @@ -0,0 +1,481 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:17:25 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +CONFIG_ARCH_ATMEL=y +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x01000000 +CONFIG_DRAM_SIZE=0x00400000 +CONFIG_FLASH_MEM_BASE=0x01400000 +CONFIG_FLASH_SIZE=0x00400000 +# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set + +# +# ATMEL Options +# +CONFIG_ARM_CLK=40000000 +CONFIG_SKIP_DUMP_CPU_INFO=y +CONFIG_MEM16_BASE=0x03000000 +CONFIG_MEM8_BASE=0x03000000 +CONFIG_IO16_BASE=0x02000000 +CONFIG_IO8_BASE=0x02000000 +CONFIG_CPU_AT91X40=y +# CONFIG_CPU_AT91X63 is not set +# CONFIG_ATMEL_DEBUG is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_CPU_32v4=y +CONFIG_CPU_CACHE_V4=y + +# +# Processor Features +# + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram initrd=0x01300000,768K keepinitrd" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=2048 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DCC is not set +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_SYSFS is not set +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/configs/espd_4510b_defconfig b/arch/arm/configs/espd_4510b_defconfig new file mode 100644 index 00000000..c053d8e5 --- /dev/null +++ b/arch/arm/configs/espd_4510b_defconfig @@ -0,0 +1,648 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:27:49 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +CONFIG_ARCH_ESPD_4510B=y +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x01800000 +CONFIG_FLASH_SIZE=0x00200000 +CONFIG_ARM_CLK=50000000 +CONFIG_SKIP_DUMP_CPU_INFO=y +CONFIG_REMAP_VECTORS_TO_RAM=y + +# +# ESPD_4510B Options +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_S3C4510B=y +CONFIG_CPU_32v4=y + +# +# Processor Features +# + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,19200 root=/dev/ram0 rw initrd=0xA00000,2048K keepinitrd ip=192.168.5.7:192.168.5.103:192.168.5.103:255.255.255.0:ARM7:eth0:any elevator=noop" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +CONFIG_BINFMT_SHARED_FLAT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_UNIX is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +CONFIG_ETH_S3C4510B=y +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DCC is not set +CONFIG_SERIAL_S3C4510B=y +CONFIG_SERIAL_S3C4510B_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y diff --git a/arch/arm/configs/ks8695_config b/arch/arm/configs/ks8695_config new file mode 100644 index 00000000..4aa007f9 --- /dev/null +++ b/arch/arm/configs/ks8695_config @@ -0,0 +1,648 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15 +# Tue Feb 28 14:13:11 2006 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_KOBJECT_UEVENT is not set +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +CONFIG_ARCH_KS8695=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set + +# +# Kendin-Micrel KS8695 Implementation Options +# + +# +# KS8695 Platforms +# +CONFIG_MACH_KS8695=y +# CONFIG_MACH_CM4002 is not set +# CONFIG_MACH_CM4008 is not set +# CONFIG_MACH_CM40xx is not set +# CONFIG_MACH_LITE300 is not set +# CONFIG_MACH_SE4200 is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM922T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram0" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +CONFIG_FPE_FASTFPE=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +CONFIG_ETH_KS8695=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_KS8695=y +CONFIG_SERIAL_KS8695_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +CONFIG_FRAME_POINTER=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_ERRORS is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y diff --git a/arch/arm/configs/lpc22xx_defconfig b/arch/arm/configs/lpc22xx_defconfig new file mode 100644 index 00000000..ae04a6ec --- /dev/null +++ b/arch/arm/configs/lpc22xx_defconfig @@ -0,0 +1,451 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11.8-hsc0 +# Thu Jun 16 14:26:43 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +CONFIG_ARCH_LPC22xx=y +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x81000000 +CONFIG_DRAM_SIZE=0x00800000 +CONFIG_FLASH_MEM_BASE=0x80000000 +CONFIG_FLASH_SIZE=0x00400000 +# CONFIG_ARCH_SUPPORTS_BIG_ENDIAN is not set +CONFIG_ARM_CLK=40000000 +CONFIG_SKIP_DUMP_CPU_INFO=y +CONFIG_REMAP_VECTORS_TO_RAM=y + +# +# LPC22xx Options +# +CONFIG_LPC22xx_Fosc=10000000 + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_LPC22xx=y +CONFIG_CPU_32v4=y + +# +# Processor Features +# + +# +# General setup +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_XIP_KERNEL is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# At least one math emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_PM is not set +CONFIG_PREEMPT=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/ram0 initrd=0x81200000,1000K console=ttyS0" +# CONFIG_ALIGNMENT_TRAP is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Userland interfaces +# + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set + +# +# Input Device Drivers +# + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=0 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DCC is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + diff --git a/arch/arm/configs/p2001_defconfig b/arch/arm/configs/p2001_defconfig new file mode 100644 index 00000000..53112faf --- /dev/null +++ b/arch/arm/configs/p2001_defconfig @@ -0,0 +1,633 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:58:26 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_KOBJECT_UEVENT is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +CONFIG_ARCH_P2001=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x40000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x02000000 +CONFIG_FLASH_SIZE=0x00400000 +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# P2001 Options +# +CONFIG_SYSCLK=73728000 +CONFIG_P2001_AUTO_DETECT_SDRAM=y +CONFIG_P2001_WATCHDOG=y +# CONFIG_P2001_TIMER2_LED_FREQ_INDICATOR is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM9TDMI=y +CONFIG_CPU_32v4=y +CONFIG_CPU_CACHE_V4=y + +# +# Processor Features +# + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="ip=dhcp root=/dev/nfs console=ttyS0,57600n8" +# CONFIG_XIP_KERNEL is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_P2001=m + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +CONFIG_FPE_NWFPE_XP=y +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +CONFIG_BINFMT_SHARED_FLAT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +CONFIG_DEBUG_DRIVER=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_P2001_ETH=y +# CONFIG_P2001_ETH_RMII is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DCC is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_P2001_UART=y +CONFIG_SERIAL_P2001_UART_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=64 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y diff --git a/arch/arm/configs/s3c24a0_mmu_defconfig b/arch/arm/configs/s3c24a0_mmu_defconfig new file mode 100644 index 00000000..37e4a540 --- /dev/null +++ b/arch/arm/configs/s3c24a0_mmu_defconfig @@ -0,0 +1,522 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm2-hsc0 +# Wed May 4 09:09:31 2005 +# +CONFIG_ARM=y +CONFIG_MMU=y +# CONFIG_MPU is not set +# CONFIG_NO_MU is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +CONFIG_ARCH_S3C24A0=y +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set + +# +# S3C24A0 Implementations +# +CONFIG_ARCH_SMDK24A0=y +CONFIG_ARCH_SPJ=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# Bus support +# +CONFIG_ISA=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram initrd=0x10800000,4M keepinitrd" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_DCC=y +CONFIG_SERIAL_DCC_CONSOLE=y +# CONFIG_SERIAL_S3C24A0 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/configs/s3c24a0_nommu_defconfig b/arch/arm/configs/s3c24a0_nommu_defconfig new file mode 100644 index 00000000..1ec8df79 --- /dev/null +++ b/arch/arm/configs/s3c24a0_nommu_defconfig @@ -0,0 +1,518 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 14:28:27 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +CONFIG_ARCH_S3C24A0=y +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x10000000 +CONFIG_DRAM_SIZE=0x04000000 +CONFIG_FLASH_MEM_BASE=0x00400000 +CONFIG_FLASH_SIZE=0x00400000 + +# +# S3C24A0 Implementations +# +CONFIG_ARCH_SMDK24A0=y +CONFIG_ARCH_SPJ=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_CPU_MXU_ENABLE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# Bus support +# +CONFIG_ISA=y +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram initrd=0x10800000,4M keepinitrd" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_DCC=y +CONFIG_SERIAL_DCC_CONSOLE=y +# CONFIG_SERIAL_S3C24A0 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y diff --git a/arch/arm/configs/s3c3410_defconfig b/arch/arm/configs/s3c3410_defconfig new file mode 100644 index 00000000..48c605cf --- /dev/null +++ b/arch/arm/configs/s3c3410_defconfig @@ -0,0 +1,469 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:55:42 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +CONFIG_ARCH_S3C3410=y +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +# CONFIG_SET_MEM_PARAM is not set +CONFIG_DRAM_BASE=0x01000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x00000000 +CONFIG_FLASH_SIZE=0x00200000 +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y +CONFIG_ARM_CLK=40000000 +CONFIG_SKIP_DUMP_CPU_INFO=y + +# +# S3C3410 Options +# +CONFIG_REMAP_VECTORS_TO_RAM=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_CPU_32v4=y +CONFIG_CPU_CACHE_V4=y + +# +# Processor Features +# +CONFIG_CPU_BIG_ENDIAN=y + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="ramdisk=8192 initrd=0x01300000,1M keepinitrd root=/dev/ram" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_DCC=y +CONFIG_SERIAL_DCC_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +# CONFIG_PROC_FS is not set +# CONFIG_SYSFS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/configs/s3c44b0x_defconfig b/arch/arm/configs/s3c44b0x_defconfig new file mode 100644 index 00000000..cefe65a7 --- /dev/null +++ b/arch/arm/configs/s3c44b0x_defconfig @@ -0,0 +1,618 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:57:35 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_KOBJECT_UEVENT is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_S5C7375 is not set +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +CONFIG_ARCH_S3C44B0=y +# CONFIG_ARCH_P2001 is not set +# CONFIG_SET_MEM_PARAM is not set +CONFIG_DRAM_BASE=0x0C000000 +CONFIG_DRAM_SIZE=0x01000000 +CONFIG_FLASH_MEM_BASE=0x00000000 +CONFIG_FLASH_SIZE=0x00200000 +CONFIG_ARM_CLK=60000000 +CONFIG_SKIP_DUMP_CPU_INFO=y +CONFIG_REMAP_VECTORS_TO_RAM=y + +# +# S3C44B0X Board Options +# +# CONFIG_DEBUG_NICKMIT is not set +# CONFIG_ARM_CLK_ADJUST is not set + +# +# S3C44B0X Board Driver Options +# +CONFIG_SERIAL_S3C44B0X=y +# CONFIG_SERIAL_S3C44B0X_CONSOLE is not set +# CONFIG_ETH_RTL8019AS is not set +# CONFIG_S3C44B0X_GPIO_LED is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_CPU_32v4=y +CONFIG_CPU_CACHE_V4=y + +# +# Processor Features +# + +# +# Bus support +# +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=1024 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_DCC=y +CONFIG_SERIAL_DCC_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/configs/s5c7375_defconfig b/arch/arm/configs/s5c7375_defconfig new file mode 100644 index 00000000..078e3ecd --- /dev/null +++ b/arch/arm/configs/s5c7375_defconfig @@ -0,0 +1,482 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc3-mm3-hsc0 +# Fri May 6 20:51:37 2005 +# +CONFIG_ARM=y +# CONFIG_MMU is not set +# CONFIG_MPU is not set +CONFIG_NO_MU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set +CONFIG_ARCH_S5C7375=y +# CONFIG_ARCH_S3C24A0 is not set +# CONFIG_ARCH_S3C2500 is not set +# CONFIG_ARCH_ATMEL is not set +# CONFIG_ARCH_S3C3410 is not set +# CONFIG_ARCH_ESPD_4510B is not set +# CONFIG_ARCH_S3C44B0 is not set +# CONFIG_ARCH_P2001 is not set +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x00000000 +CONFIG_DRAM_SIZE=0x00400000 +CONFIG_FLASH_MEM_BASE=0x08000000 +CONFIG_FLASH_SIZE=0x00200000 + +# +# S5C7375 Options +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM920T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_CACHE_VIVT=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_CPU_MXU_ENABLE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_ISA_DMA_API=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_PREEMPT=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_FLATMEM=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram initrd=0x00300000,768K keepinitrd" +# CONFIG_XIP_KERNEL is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=2048 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_IEEE80211 is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_DCC=y +CONFIG_SERIAL_DCC_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_SYSFS is not set +# CONFIG_DEVFS_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1320a0ef..9f062921 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -1,5 +1,6 @@ # # Makefile for the linux kernel. +# modified for uClinux by Hyok S. Choi, 2004 # AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) @@ -20,6 +21,7 @@ obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o +obj-$(CONFIG_INITRD_MTD) += initrd-mtd.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 4779f474..c1ebcb60 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -178,3 +178,12 @@ EXPORT_SYMBOL(_find_next_zero_bit_be); EXPORT_SYMBOL(_find_first_bit_be); EXPORT_SYMBOL(_find_next_bit_be); #endif + +#if 1 // add by Victor Yu. 03-08-2007 +int moxa_gpio_sd_used_flag=0; +EXPORT_SYMBOL(moxa_gpio_sd_used_flag); +#endif +#if 1 // add by Victor Yu. 04-03-2007 +int lcm_module_flag=0; +EXPORT_SYMBOL(lcm_module_flag); +#endif diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 6f5e7c50..25641c65 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -9,9 +9,23 @@ */ #include +#include #include "entry-header.S" +#if !defined(CONFIG_MMU) +#define sys_madvise sys_ni_syscall +#define sys_readahead sys_ni_syscall +#define sys_mprotect sys_ni_syscall +#define sys_msync sys_ni_syscall +#define sys_mlock sys_ni_syscall +#define sys_munlock sys_ni_syscall +#define sys_mlockall sys_ni_syscall +#define sys_munlockall sys_ni_syscall +#define sys_mremap sys_ni_syscall +#define sys_mincore sys_ni_syscall +#define sys_remap_file_pages sys_ni_syscall +#endif /* CONFIG_MMU */ .align 5 /* diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index f359a189..eb61ac64 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -21,6 +21,7 @@ #include #include #include +#include /* * Kernel startup entry point. @@ -34,9 +35,29 @@ * numbers for r1. * */ +#if 0 /* add by Victor Yu. 02-08-2007 for debug */ + .macro victor_led value + ldr r2, =0x98700000 + ldr r3, [r2] + and r3, r3, #0xfffffff0 + orr r3, r3, \value + str r3, [r2] + .endm + + .macro victor_uart value + ldr r7, =0x98200000 + mov r8, \value + strb r8, [r7] + .endm +#endif __INIT .type stext, %function ENTRY(stext) +#if 1 /* add by Victor Yu. 02-08-2007 */ + mov r1, #MACH_TYPE_MOXART +#else + ldr r1, =machine_arch_type @ find the machine type +#endif msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 @@ -46,7 +67,7 @@ ENTRY(stext) #endif bl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? - beq __error_p @ yes, error 'p' + beq __error_p @ yes, error 'p' bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a' @@ -70,12 +91,16 @@ __after_proc_init: #endif #ifdef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CR_C +#else /* add by Victor Yu. 02-09-2007 */ + orr r0, r0, #CR_C #endif #ifdef CONFIG_CPU_BPREDICT_DISABLE bic r0, r0, #CR_Z #endif #ifdef CONFIG_CPU_ICACHE_DISABLE bic r0, r0, #CR_I +#else /* add by Victor Yu. 02-09-2007 */ + orr r0, r0, #CR_I #endif #ifdef CONFIG_CPU_HIGH_VECTOR orr r0, r0, #CR_V @@ -83,6 +108,10 @@ __after_proc_init: bic r0, r0, #CR_V #endif mcr p15, 0, r0, c1, c0, 0 @ write control reg +#if 0 /* add by Victor Yu. 02-08-2007 */ + mov ip, #0 + mcr p15, 0, ip, c7, c5, 4 @ flush prefetch instruction +#endif #endif /* CONFIG_CPU_CP15 */ mov pc, r13 @ clear the BSS and jump diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index ebc3e74a..777019db 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -70,6 +70,9 @@ __INIT .type stext, %function ENTRY(stext) +#if 1 /* add by Victor Yu. 02-08-2007 */ + mov r1, #MACH_TYPE_MOXART +#endif msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id diff --git a/arch/arm/kernel/initrd-mtd.c b/arch/arm/kernel/initrd-mtd.c new file mode 100644 index 00000000..6da908ac --- /dev/null +++ b/arch/arm/kernel/initrd-mtd.c @@ -0,0 +1,55 @@ +/* + * arch/arm/kernel/initrd-mtd.c + * + * MTD RAM platform device for the initrd + * + * Copyright (C) 2006 Philip Craig + * + */ + +#include +#include +#include +#include + +extern unsigned long phys_initrd_start; +extern unsigned long phys_initrd_size; + +static struct resource initrd_mtd_ram_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platdata_mtd_ram initrd_mtd_ram_data = { + .mapname = "Romfs", + .root_dev = 1, +}; + +static struct platform_device initrd_mtd_ram_device = { + .name = "mtd-ram", + .id = 0, + .dev.platform_data = &initrd_mtd_ram_data, + .num_resources = 1, + .resource = &initrd_mtd_ram_resource, +}; + +static int __init initrd_device_setup(void) +{ + int ret = 0; + + if (phys_initrd_start) { + if (map_bankwidth_supported(4)) + initrd_mtd_ram_data.bankwidth = 4; + else if (map_bankwidth_supported(2)) + initrd_mtd_ram_data.bankwidth = 2; + else + initrd_mtd_ram_data.bankwidth = 1; + initrd_mtd_ram_resource.start = phys_initrd_start; + initrd_mtd_ram_resource.end = phys_initrd_start + + phys_initrd_size - 1; + ret = platform_device_register(&initrd_mtd_ram_device); + } + + return ret; +} + +__initcall(initrd_device_setup); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index bf35c178..7a567b17 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -173,8 +173,17 @@ int __init reboot_setup(char *str) __setup("reboot=", reboot_setup); +#if 1 // add by Victor Yu. 03-06-2007 + #if defined(CONFIG_ARCH_W311_TEST) // add by Victor Yu. 07-10-2008 +#define SW_READY_LED_OFF() *(volatile unsigned int *)(CPE_GPIO_BASE) |= (1<<4) + #else +#define SW_READY_LED_OFF() *(volatile unsigned int *)(CPE_GPIO_BASE) |= (1<<27) + #endif +#endif void machine_halt(void) { + SW_READY_LED_OFF(); // add by Victor Yu. 03-06-2007 + while ( 1 ); // add by Victor Yu. 02-08-2007 } @@ -182,11 +191,39 @@ void machine_power_off(void) { if (pm_power_off) pm_power_off(); + SW_READY_LED_OFF(); // add by Victor Yu. 03-06-2007 + while ( 1 ); // add by Victor Yu. 02-08-2007 } void machine_restart(char * __unused) { - arm_pm_restart(reboot_mode); + /* + * Clean and disable cache, and turn off interrupts + */ + cpu_proc_fin(); + +#ifdef CONFIG_MMU + /* + * Tell the mm system that we are going to reboot - + * we may need it to insert some 1:1 mappings so that + * soft boot works. + */ + setup_mm_for_reboot(reboot_mode); +#endif + + /* + * Now call the architecture specific reboot code. + */ + SW_READY_LED_OFF(); // add by Victor Yu. 03-06-2007 + arch_reset(reboot_mode); + + /* + * Whoops - the architecture was unable to reboot. + * Tell the user! + */ + mdelay(1000); + printk("Reboot failed -- System halted\n"); + while (1); } void __show_regs(struct pt_regs *regs) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 29efc9f8..05e4a490 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -701,7 +701,9 @@ __tagtable(ATAG_REVISION, parse_tag_revision); static int __init parse_tag_cmdline(const struct tag *tag) { +#ifndef CONFIG_CMDLINE_FORCE strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); +#endif return 0; } diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 00c18d35..43a722bf 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -3,6 +3,7 @@ * * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c * Copyright (C) 1995, 1996 Russell King. + * Copyright (C) 2003, 2004 Hyok S. Choi * * 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 @@ -114,7 +115,7 @@ sys_arm_mremap(unsigned long addr, unsigned long old_len, unsigned long new_addr) { unsigned long ret = -EINVAL; - +#ifdef CONFIG_MMU if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) goto out; @@ -123,6 +124,7 @@ sys_arm_mremap(unsigned long addr, unsigned long old_len, up_write(¤t->mm->mmap_sem); out: +#endif return ret; } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index bede380c..59d35e91 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -682,6 +682,16 @@ void abort(void) } EXPORT_SYMBOL(abort); +#ifdef CONFIG_MMU +# define VECTORS_BASE (0xffff0000) +#else +# ifndef CONFIG_REMAP_VECTORS_TO_RAM +# define VECTORS_BASE (0) +# else +# define VECTORS_BASE (CONFIG_DRAM_BASE) +# endif +#endif /* CONFIG_MMU */ + void __init trap_init(void) { unsigned long vectors = CONFIG_VECTORS_BASE; diff --git a/arch/arm/mach-adifcc/Kconfig b/arch/arm/mach-adifcc/Kconfig new file mode 100644 index 00000000..7f4075f4 --- /dev/null +++ b/arch/arm/mach-adifcc/Kconfig @@ -0,0 +1,30 @@ + +menu "ADIFCC Implementation Options" + +comment "ADI Board Types" + +config ARCH_ADI_EVB + bool "80200 EVB" + depends on ARCH_ADIFCC + help + Say Y here if you want to run your kernel on the ADI 80200EVB platform. + +config ARCH_BRH + bool "BRH" + depends on ARCH_ADIFCC + help + Say Y here if you want to run your kernel on the ADI BRH platform. + +config ARCH_QUINQUE + bool "Quinque" + depends on ARCH_ADIFCC + help + Say Y here if you want to run your kernel on the ADI Quinque platform. + + +config ARCH_SUPPORTS_BIG_ENDIAN + bool + default y if ARCH_BRH || ARCH_QUINQUE + +endmenu + diff --git a/arch/arm/mach-atmel/Kconfig b/arch/arm/mach-atmel/Kconfig new file mode 100644 index 00000000..1d783ce6 --- /dev/null +++ b/arch/arm/mach-atmel/Kconfig @@ -0,0 +1,61 @@ +menu "ATMEL Options" + depends on ARCH_ATMEL + +config ARCH_SUPPORTS_BIG_ENDIAN + bool "big endian mode" + default n + help + AT91 core supports both of little and big endian. + +config ARM_CLK + int 'Arm Core Clock' + default 40000000 + help + The default host clock of EB01 is 40MHz. + Otherwise, change the value in clock. + +config SKIP_DUMP_CPU_INFO + bool + default y + help + AT91(ARM7TDMI) core does not support cache size + recognition instructions which uses MMU features. + +config MEM16_BASE + hex 'Memory mapped 16-bit io base' + default 0x03000000 + +config MEM8_BASE + hex 'Memory mapped 8-bit io base' + default 0x03000000 + +config IO16_BASE + hex '16-bit io base' + default 0x02000000 + +config IO8_BASE + hex '8-bit io base' + default 0x02000000 + +choice + prompt "Atmel CPU" + default CPU_AT91X40 + +config CPU_AT91X40 + bool "AT91x40" + +config CPU_AT91X63 + bool "AT91X63" + +endchoice + +config ATMEL_DEBUG + bool "Atmel Kernel-Debug hack" + default n + +config AT91_DEBUG_BASE + depends on ATMEL_DEBUG + hex 'Debug buffer address' + default 0x01400000 + +endmenu diff --git a/arch/arm/mach-atmel/Makefile b/arch/arm/mach-atmel/Makefile new file mode 100644 index 00000000..1e37ca33 --- /dev/null +++ b/arch/arm/mach-atmel/Makefile @@ -0,0 +1 @@ +obj-y += arch.o irq.o time.o diff --git a/arch/arm/mach-atmel/Makefile.boot b/arch/arm/mach-atmel/Makefile.boot new file mode 100644 index 00000000..7a892b2b --- /dev/null +++ b/arch/arm/mach-atmel/Makefile.boot @@ -0,0 +1,2 @@ + zreladdr-y := 0x01000000 +initrd_phys-y := 0x01300000 diff --git a/arch/arm/mach-atmel/arch.c b/arch/arm/mach-atmel/arch.c new file mode 100644 index 00000000..4fc57dbf --- /dev/null +++ b/arch/arm/mach-atmel/arch.c @@ -0,0 +1,38 @@ +/* + * linux/arch/arm/mach-atmel/arch.c + * + * Copyright (C) 2004 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.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 + */ +#include +#include +#include +#include +#include + +extern void atmel_time_init(void); +extern unsigned long atmel_gettimeoffset(void); + +extern void __init atmel_init_irq(void); + +extern struct sys_timer atmel_timer; + +MACHINE_START(ATMEL, "ATMEL EB01") + /* Maintainer: Hyok S. Choi */ + .init_irq = atmel_init_irq, + .timer = &atmel_timer, +MACHINE_END diff --git a/arch/arm/mach-atmel/head.S b/arch/arm/mach-atmel/head.S new file mode 100644 index 00000000..32023b6c --- /dev/null +++ b/arch/arm/mach-atmel/head.S @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-atmel/head.S + * + * Copyright (C) 2003 Hyok S. Choi + * + * + * uClinux kernel startup code for atmel + * which has no bootloader + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + ldr r2, L_AT91_SF_CIDR + ldr r2, [r2] @ read processor id + + str r2, [r6] + mov r2, #MACH_TYPE_ATMEL + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + +L_AT91_SF_CIDR: + .long 0xfff00000 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-atmel/irq.c b/arch/arm/mach-atmel/irq.c new file mode 100644 index 00000000..836f2fc3 --- /dev/null +++ b/arch/arm/mach-atmel/irq.c @@ -0,0 +1,211 @@ +/* + * linux/arch/armnommu/mach-atmel/irq.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + /* Internal Sources */ +#define LevelSensitive (0<<5) +#define EdgeTriggered (1<<5) + + /* External Sources */ +#define LowLevel (0<<5) +#define NegativeEdge (1<<5) +#define HighLevel (2<<5) +#define PositiveEdge (3<<5) + +static unsigned char eb01_irq_prtable[32] = { + 7, /* FIQ */ + 0, /* SWIRQ */ + 0, /* US0IRQ */ + 0, /* US1IRQ */ + 2, /* TC0IRQ */ + 2, /* TC1IRQ */ + 2, /* TC2IRQ */ + 0, /* WDIRQ */ + 0, /* PIOAIRQ */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 1, /* IRQ0 */ + 0, /* IRQ1 */ + 0, /* IRQ2 */ +}; + +static unsigned char eb01_irq_type[32] = { + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + + EdgeTriggered, /* IRQ0 = neg. edge */ + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, + EdgeTriggered, +}; + +void __inline__ at91_mask_irq(unsigned int irq) +{ + unsigned long mask = 1 << (irq); + __raw_writel(mask, AIC_IDCR); +} + +void __inline__ at91_unmask_irq(unsigned int irq) +{ + unsigned long mask = 1 << (irq); + __raw_writel(mask, AIC_IECR); +} + +void __inline__ at91_mask_ack_irq(unsigned int irq) +{ + at91_mask_irq(irq); +} + +void __inline__ at91_end_of_isr(void) +{ + /* Indicates end of ISR to AIC */ + __raw_writel(0x1L, AIC_EOICR); /* AIC don't care the value */ +} + +void __inline__ at91_unmask_and_eoi(unsigned int irq) +{ + at91_unmask_irq(irq); + at91_end_of_isr(); +} + +static struct irqchip at91_chip = { + .ack = at91_mask_ack_irq, + .mask = at91_mask_irq, + .unmask = at91_unmask_and_eoi, +}; + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct sysdev_class irq_class = { + set_kset_name("irq"), + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init atmel_init_irq(void) +{ + int irq; + + /* Disable all interrupts */ + __raw_writel(0xFFFFFFFF, AIC_IDCR); + + /* Clear all interrupts */ + __raw_writel(0xFFFFFFFF, AIC_ICCR); + + for ( irq = 0 ; irq < 32 ; irq++ ) { + __raw_writel(irq, AIC_EOICR); + } + + for ( irq = 0 ; irq < 32 ; irq++ ) { + __raw_writel(eb01_irq_prtable[irq] | eb01_irq_type[irq], + AIC_SMR(irq)); + } + + for (irq = 0; irq < NR_IRQS; irq++) { + if (!VALID_IRQ(irq)) continue; + set_irq_chip(irq, &at91_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } +} diff --git a/arch/arm/mach-atmel/time.c b/arch/arm/mach-atmel/time.c new file mode 100644 index 00000000..182f38e3 --- /dev/null +++ b/arch/arm/mach-atmel/time.c @@ -0,0 +1,104 @@ +/* + * linux/arch/armnommu/mach-atmel/time.c + * + * Copyright (C) SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +unsigned long atmel_gettimeoffset (void) +{ + volatile struct at91_timers* tt = (struct at91_timers*) (AT91_TC_BASE); + volatile struct at91_timer_channel* tc = &tt->chans[KERNEL_TIMER].ch; + return tc->cv * (1000*1000)/(ARM_CLK/128); +} + +static irqreturn_t +atmel_timer_interrupt(int irq, void *dev_id) +{ + /* Clear the timer status interrupt. */ + volatile struct at91_timers* tt = (struct at91_timers*) (AT91_TC_BASE); + volatile struct at91_timer_channel* tc = &tt->chans[KERNEL_TIMER].ch; + (void)tc->sr; + + timer_tick(); + return IRQ_HANDLED; +} + +static struct irqaction atmel_timer_irq = { + .name = "ATMEL Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = atmel_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ + +void __init atmel_time_init (void) +{ + register volatile struct at91_timers* tt = (struct at91_timers*) (AT91_TC_BASE); + register volatile struct at91_timer_channel* tc = &tt->chans[KERNEL_TIMER].ch; + unsigned long v; + + /* enable Kernel timer */ + HW_AT91_TIMER_INIT(KERNEL_TIMER) + + /* No SYNC */ + tt->bcr = 0; + /* program NO signal on XC1 */ + v = tt->bmr; + v &= ~TCNXCNS(KERNEL_TIMER,3); + v |= TCNXCNS(KERNEL_TIMER,1); + tt->bmr = v; + + tc->ccr = 2; /* disable the channel */ + + /* select ACLK/128 as inupt frequency for TC1 and enable CPCTRG */ + tc->cmr = 3 | (1 << 14); + + tc->idr = ~0ul; /* disable all interrupt */ + tc->rc = ((ARM_CLK/128)/HZ - 1); /* load the count limit into the CR register */ + tc->ier = TC_CPCS; /* enable CPCS interrupt */ + + /* + * @todo do those really need to be function pointers ? + */ + atmel_timer_irq.handler = atmel_timer_interrupt; + + /* set up the interrupt */ + setup_irq(KERNEL_TIMER_IRQ_NUM, &atmel_timer_irq); + + /* enable the channel */ + tc->ccr = TC_SWTRG|TC_CLKEN; +} + +struct sys_timer atmel_timer = { + .init = atmel_time_init, + .offset = atmel_gettimeoffset, +}; diff --git a/arch/arm/mach-espd_4510b/Kconfig b/arch/arm/mach-espd_4510b/Kconfig new file mode 100644 index 00000000..8f117432 --- /dev/null +++ b/arch/arm/mach-espd_4510b/Kconfig @@ -0,0 +1,26 @@ +menu "ESPD_4510B Options" + depends on ARCH_ESPD_4510B + +config ARM_CLK + int 'Arm Core Clock' + default 50000000 + help + the default host clock of S3C4510B is 50MHz. + otherwise, change the value in clock. + +config SKIP_DUMP_CPU_INFO + bool + default y + help + S3C4510B(ARM7TDMI) core does not support cache size + recognition instructions which uses MMU features. + +config REMAP_VECTORS_TO_RAM + bool + default y + help + S3C4510B core does not support ROM and RAM remap + function. we set the trap_init to be initialized + at the begining of DRAM_BASE. + +endmenu diff --git a/arch/arm/mach-espd_4510b/Makefile b/arch/arm/mach-espd_4510b/Makefile new file mode 100644 index 00000000..41084302 --- /dev/null +++ b/arch/arm/mach-espd_4510b/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o mm.o dma.o time.o diff --git a/arch/arm/mach-espd_4510b/Makefile.boot b/arch/arm/mach-espd_4510b/Makefile.boot new file mode 100644 index 00000000..c7e75acf --- /dev/null +++ b/arch/arm/mach-espd_4510b/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 + diff --git a/arch/arm/mach-espd_4510b/arch.c b/arch/arm/mach-espd_4510b/arch.c new file mode 100644 index 00000000..2b573750 --- /dev/null +++ b/arch/arm/mach-espd_4510b/arch.c @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-espd_4510b/arch.c + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void __init s3c4510b_init_irq(void); +extern struct sys_timer s3c4510b_timer; + +void __init s3c4510b_init_machine(void) { + /* enable LED 0 */ + outl( 0xFE, REG_IOPDATA); +} + +MACHINE_START(ESPD_4510B, "ESPD 4510B(S3C4510B)") + /* Maintainer: Curt Brune */ + .init_irq = s3c4510b_init_irq, + .init_machine = s3c4510b_init_machine, + .boot_params = 0x00000800, + .timer = &s3c4510b_timer, +MACHINE_END diff --git a/arch/arm/mach-espd_4510b/dma.c b/arch/arm/mach-espd_4510b/dma.c new file mode 100644 index 00000000..05b99370 --- /dev/null +++ b/arch/arm/mach-espd_4510b/dma.c @@ -0,0 +1,26 @@ +/* + * arch/arm/arch-espd_4510b/dma.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co., Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void arch_dma_init(dma_t *dma) +{ +} diff --git a/arch/arm/mach-espd_4510b/head.S b/arch/arm/mach-espd_4510b/head.S new file mode 100644 index 00000000..3044cfc4 --- /dev/null +++ b/arch/arm/mach-espd_4510b/head.S @@ -0,0 +1,96 @@ +/* + * linux/arch/armnommu/mach-espd_4510b/head.S + * + * Copyright (C) 2003 Hyok S. Choi + * + * + * uClinux kernel startup code for s3c4510b + */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + /* cache clean and flush +/* + * cf. Ch-5 of S3C4510 user's manual for + * "Cache flush operation" + * To clear Tag RAM area. + */ + ldr r4, =0x11000000 + mov r5, #0 + mov r0, #256 +cache_flush_loop: + str r5, [r4], #4 + subs r0, r0, #1 + bne cache_flush_loop + + /* cache/write buffer on */ + ldr r0, =0x3FF0000 @ SYSCFG + ldr r2, [r0] + bic r2, r2, #0x30 + orr r2, r2, #0x10 @ 0-Kbyte SRAM, 8-Kbyte cache + orr r2, r2, #6 @ Cache and write buffer + str r2, [r0] + + ldr r5, =REG_IOPDATA + /* P0: LED, P2: ETH_MDDIS */ + ldr r4, =0xFA + str r4, [r5] + + ldr r2, S3C4510B_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, ESPD_4510B_MACH_TYPE + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + +S3C4510B_PROCESSOR_TYPE: + .long 0x36807001 +ESPD_4510B_MACH_TYPE: + .long MACH_TYPE_ESPD_4510B + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-espd_4510b/irq.c b/arch/arm/mach-espd_4510b/irq.c new file mode 100644 index 00000000..80f576b9 --- /dev/null +++ b/arch/arm/mach-espd_4510b/irq.c @@ -0,0 +1,122 @@ +/* + * linux/arch/armnommu/mach-espd_4510b/irq.c + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * based the codes by + * 2003 Thomas Eschenbacher + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +static void __s3c4510b_mask_irq(unsigned int irq) +{ + INT_DISABLE( irq); +} + +static void __s3c4510b_unmask_irq(unsigned int irq) +{ + INT_ENABLE( irq); +} + +static void __s3c4510b_ack_irq(unsigned int irq) +{ + /* Acknowledge, clear _AND_ disable the interrupt. */ + INT_DISABLE( irq); + CLEAR_PEND_INT( irq); +} + +static struct irqchip s3c4510b_chip = { + .ack = __s3c4510b_ack_irq, + .mask = __s3c4510b_mask_irq, + .unmask = __s3c4510b_unmask_irq, +}; + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct sysdev_class irq_class = { + set_kset_name("irq"), + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init s3c4510b_init_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &s3c4510b_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* mask and disable all further interrupts */ + outl(INT_MASK_DIS, REG_INTMASK); + + /* set all to IRQ mode, not FIQ */ + outl(INT_MODE_IRQ, REG_INTMODE); + + /* Clear Intrerrupt pending register */ + outl( 0x1FFFFF, REG_INTPEND); + + /* + * enable the gloabal interrupt flag, this should be + * safe now, all sources are masked out and acknowledged + */ + INT_ENABLE( INT_GLOBAL); +} + diff --git a/arch/arm/mach-espd_4510b/mm.c b/arch/arm/mach-espd_4510b/mm.c new file mode 100644 index 00000000..8663b507 --- /dev/null +++ b/arch/arm/mach-espd_4510b/mm.c @@ -0,0 +1,17 @@ +/* + * linux/arch/armnommu/mach-espd_4510b/mm.c + * + * Copyright(C)2003 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#include +#include +#include + +#include +#include +#include +#include + +#include diff --git a/arch/arm/mach-espd_4510b/time.c b/arch/arm/mach-espd_4510b/time.c new file mode 100644 index 00000000..82ee48a5 --- /dev/null +++ b/arch/arm/mach-espd_4510b/time.c @@ -0,0 +1,118 @@ +/* + * linux/arch/armnommu/mach-espd_4510b/time.c + * + * Copyright (C) SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define CLOCKS_PER_USEC (CONFIG_ARM_CLK/1000000) + +static volatile unsigned long timer_cnt; + +unsigned long s3c4510b_gettimeoffset (void) +{ + unsigned long usec; + + /* returns microseconds -- timer 1 is free running in countdown mode */ + usec = 0xFFFFFFFF - inl( REG_TCNT1); + usec /= CLOCKS_PER_USEC; + + return usec; +} + +static irqreturn_t +s3c4510b_timer_interrupt(int irq, void *dev_id) +{ + + timer_cnt++; + +#ifdef CONFIG_ARCH_ESPD_4510B + if ( ! (timer_cnt % (HZ/4))) { + LED_TOGGLE(0); + } +#endif + timer_tick(); + + return IRQ_HANDLED; +} + +static struct irqaction s3c4510b_timer_irq = { + .name = "S3C4510b Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = s3c4510b_timer_interrupt +}; + + +/* + * Set up timer interrupt + */ + +void __init s3c4510b_time_init (void) +{ + u_int32_t period; + + /* + * disable and clear timers 0 and 1. set both timers to + * interval mode. + */ + outl( 0x0, REG_TMOD); + /* clear any pending interrupts */ + outl( 0x1FFFFF, REG_INTPEND); + + timer_cnt = 0; + + /* initialize the timer period */ + period = (CLOCK_TICK_RATE / HZ); + outl( period, REG_TDATA0); + + /* set timer1 to continually count down from FFFFFFFF */ + outl( 0xFFFFFFFF, REG_TDATA1); + +// printk(KERN_INFO "time_init(): TICK_RATE: %u, HZ: %u, period: %u\n", CLOCK_TICK_RATE, HZ, period); + + s3c4510b_timer_irq.handler = s3c4510b_timer_interrupt; + + /* set up the interrupt vevtor for timer 0 match */ + setup_irq( INT_TIMER0, &s3c4510b_timer_irq); + + /* enable the timer IRQ */ + INT_ENABLE( INT_TIMER0); + + /* let timer 0 run... */ + outl( TM0_RUN | TM1_RUN, REG_TMOD); +} + +struct sys_timer s3c4510b_timer = { + .init = s3c4510b_time_init, + .offset = s3c4510b_gettimeoffset, +}; + diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 771b65bf..e854678e 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -48,14 +48,24 @@ #define INTCP_PA_CLCD_BASE 0xc0000000 +#ifdef CONFIG_MMU #define INTCP_VA_CIC_BASE 0xf1000040 #define INTCP_VA_PIC_BASE 0xf1400000 #define INTCP_VA_SIC_BASE 0xfca00000 +#else +#define INTCP_VA_CIC_BASE 0x10000040 +#define INTCP_VA_PIC_BASE 0x14000000 +#define INTCP_VA_SIC_BASE 0xca000000 +#endif #define INTCP_PA_ETH_BASE 0xc8000000 #define INTCP_ETH_SIZE 0x10 +#ifdef CONFIG_MMU #define INTCP_VA_CTRL_BASE 0xfcb00000 +#else +#define INTCP_VA_CTRL_BASE 0xcb000000 +#endif #define INTCP_FLASHPROG 0x04 #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) @@ -73,6 +83,7 @@ * f1b00000 1b000000 GPIO */ +#ifdef CONFIG_MMU static struct map_desc intcp_io_desc[] __initdata = { { .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), @@ -136,6 +147,7 @@ static void __init intcp_map_io(void) { iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); } +#endif #define cic_writel __raw_writel #define cic_readl __raw_readl @@ -393,8 +405,8 @@ static struct platform_device *intcp_devs[] __initdata = { */ static unsigned int mmc_status(struct device *dev) { - unsigned int status = readl(0xfca00004); - writel(8, 0xfcb00008); + unsigned int status = readl(INTCP_VA_SIC_BASE + 4); + writel(8, INTCP_VA_CTRL_BASE + 8); return status & 8; } @@ -581,9 +593,13 @@ static struct sys_timer cp_timer = { MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ .phys_io = 0x16000000, +#ifdef CONFIG_MMU .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc, +#endif .boot_params = 0x00000100, +#ifdef CONFIG_MMU .map_io = intcp_map_io, +#endif .init_irq = intcp_init_irq, .timer = &cp_timer, .init_machine = intcp_init, diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 57f23b46..e58c9142 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -1,3 +1,4 @@ + if ARCH_IXP4XX config ARCH_SUPPORTS_BIG_ENDIAN @@ -63,15 +64,90 @@ config MACH_IXDP465 config ARCH_IXCDP1100 bool depends on ARCH_IXDP425 + select DMABOUNCE + select PCI default y config ARCH_PRPMC1100 bool "PrPMC1100" + select DMABOUNCE + select PCI help Say 'Y' here if you want your kernel to support the Motorola PrPCM1100 Processor Mezanine Module. For more information on this platform, see . +config ARCH_SE4000 + bool "SnapGear SE4000" + select DMABOUNCE + select PCI + depends on ARCH_IXP4XX + help + Support for SnapGear SE4000 VPN Router. + +config MACH_SG560 + bool "SnapGear SG560" + depends on ARCH_IXP4XX + help + Support for SnapGear SG560 VPN Router. + +config MACH_SG565 + bool "SnapGear SG565" + select DMABOUNCE + select PCI + depends on ARCH_IXP4XX + help + Support for SnapGear SG565 VPN Router. + +config MACH_SG580 + bool "SnapGear SG580" + depends on ARCH_IXP4XX + help + Support for SnapGear SG580 VPN Router. + +config MACH_SG590 + bool "SecureComputing SG590" + select DMABOUNCE + select PCI + depends on ARCH_IXP4XX + help + Support for Secure Computing SG590 VPN Router. + +config MACH_SG640 + bool "SecureComputing SG640" + depends on ARCH_IXP4XX + help + Support for SecureComputing SG640 PCI Router. + +config MACH_SGARMAUTO + bool "SecureComputing 'AutoSelect' ARM Platform" + depends on ARCH_IXP4XX + help + Support for SecureComputing generic ARM platform based on IXP4XX. + +config MACH_ESS710 + bool "SnapGear SG710" + select DMABOUNCE + select PCI + depends on ARCH_IXP4XX + help + Support for SnapGear SG710 VPN Router. + +config MACH_SG720 + bool "SnapGear SG720" + select DMABOUNCE + select PCI + depends on ARCH_IXP4XX + help + Support for SnapGear SG720 VPN Router. + +config MACH_SG8100 + bool "SecureComputing SG8100" + select PCI + depends on ARCH_IXP4XX + help + Support for Secure Computing SG8100 Internet VPN Router. + config MACH_NAS100D bool prompt "NAS100D" @@ -87,6 +163,8 @@ config MACH_NAS100D config ARCH_IXDP4XX bool depends on ARCH_IXDP425 || ARCH_AVILA || MACH_IXDP465 + select DMABOUNCE + select PCI default y # @@ -94,7 +172,7 @@ config ARCH_IXDP4XX # config CPU_IXP46X bool - depends on MACH_IXDP465 + depends on MACH_IXDP465 || MACH_SG590 || MACH_SG720 default y config MACH_GTWX5715 @@ -148,6 +226,23 @@ config IXP4XX_INDIRECT_PCI need to use the indirect method instead. If you don't know what you need, leave this option unselected. +config IXP4XX_CLOCK_FORCE + bool "Select the master clock frequency" + depends on ARCH_IXP4XX + help + Some hardware platforms using the IXP4XX CPU family use a non- + standard clock frequency. Select this option so you can specify + the actual clock frequency input to the CPU. + +config IXP4XX_CLOCK + int "Select the core clock frequency" + default "66666666" + depends on IXP4XX_CLOCK_FORCE + help + You can set the actual CPU master clock frequency here, so that + you get accurate kernel timing. For example some platforms use a + 66MHz crystal instead of a 66.666666MHz. + endmenu endif diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 640315d8..bde36732 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -11,6 +11,12 @@ obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o +obj-pci-$(CONFIG_MACH_ESS710) += ess710-pci.o +obj-pci-$(CONFIG_MACH_SE5100) += ixdpg425-pci.o +obj-pci-$(CONFIG_MACH_SG565) += sg5xx-pci.o +obj-pci-$(CONFIG_MACH_SG590) += sg720-pci.o +obj-pci-$(CONFIG_MACH_SG720) += sg720-pci.o +obj-pci-$(CONFIG_MACH_SG8100) += sg5xx-pci.o obj-y += common.o @@ -20,5 +26,16 @@ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o +obj-$(CONFIG_ARCH_SE4000) += sg-setup.o +obj-$(CONFIG_MACH_SE5100) += sg-setup.o +obj-$(CONFIG_MACH_SG560) += sg-setup.o +obj-$(CONFIG_MACH_SG565) += sg-setup.o +obj-$(CONFIG_MACH_SG580) += sg-setup.o +obj-$(CONFIG_MACH_SG590) += sg-setup.o +obj-$(CONFIG_MACH_SG640) += sg-setup.o +obj-$(CONFIG_MACH_ESS710) += sg-setup.o +obj-$(CONFIG_MACH_SG720) += sg-setup.o +obj-$(CONFIG_MACH_SG8100) += sg-setup.o +obj-$(CONFIG_MACH_SGARMAUTO) += sg-setup.o obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index 9562177b..cfee81fc 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -535,3 +535,5 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) EXPORT_SYMBOL(ixp4xx_pci_read); EXPORT_SYMBOL(ixp4xx_pci_write); +EXPORT_SYMBOL(pci_set_dma_mask); +EXPORT_SYMBOL(pci_set_consistent_dma_mask); diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index fbe288a8..8f6f5b81 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-ixp4xx/common.c + * arch/arm/mach-ixp4xx/generic.c * * Generic code shared across all IXP4XX platforms * @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -143,7 +144,6 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) ixp4xx_irq_edge &= ~(1 << irq); if (line >= 8) { /* pins 8-15 */ - line -= 8; int_reg = IXP4XX_GPIO_GPIT2R; } else { /* pins 0-7 */ int_reg = IXP4XX_GPIO_GPIT1R; @@ -151,12 +151,12 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) /* Clear the style for the appropriate pin */ *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR << - (line * IXP4XX_GPIO_STYLE_SIZE)); + ((line%8) * IXP4XX_GPIO_STYLE_SIZE)); *IXP4XX_GPIO_GPISR = (1 << line); /* Set the new style */ - *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE)); + *int_reg |= (int_style << ((line%8) * IXP4XX_GPIO_STYLE_SIZE)); /* Configure the line as an input */ gpio_line_config(line, IXP4XX_GPIO_IN); diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index 13f8a7ac..68139fe4 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -128,3 +128,4 @@ MACHINE_START(IXDPG425, "Intel IXDPG425") MACHINE_END #endif + diff --git a/arch/arm/mach-ixp4xx/ess710-pci.c b/arch/arm/mach-ixp4xx/ess710-pci.c new file mode 100644 index 00000000..457e10c1 --- /dev/null +++ b/arch/arm/mach-ixp4xx/ess710-pci.c @@ -0,0 +1,75 @@ +/* + * arch/arm/mach-ixp4xx/ixdp425-pci.c + * + * ESS710 board-level PCI initialization + * Copyright (C) 2004 SnapGear - A CyberGuard Company + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +void __init ess710_pci_preinit(void) +{ + printk("PCI: reset bus...\n"); + gpio_line_set(13, 0); + gpio_line_config(13, IXP4XX_GPIO_OUT); + gpio_line_set(13, 0); + mdelay(50); + gpio_line_set(13, 1); + mdelay(50); + + gpio_line_config(6, IXP4XX_GPIO_IN); + set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW); /* INTA */ + gpio_line_config(7, IXP4XX_GPIO_IN); + set_irq_type(IRQ_IXP4XX_GPIO7, IRQT_LOW); /* INTB */ + gpio_line_config(8, IXP4XX_GPIO_IN); + set_irq_type(IRQ_IXP4XX_GPIO8, IRQT_LOW); /* INTC */ + + ixp4xx_pci_preinit(); +} + +static int __init ess710_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot == 16) + return IRQ_ESS710_PCI_INTA; + else if (slot == 15) + return IRQ_ESS710_PCI_INTB; + else if (slot == 14) + return IRQ_ESS710_PCI_INTC; + else if (slot == 13) + return IRQ_ESS710_PCI_INTC; + return -1; +} + +struct hw_pci ess710_pci __initdata = { + .nr_controllers = 1, + .preinit = ess710_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = ess710_map_irq, +}; + +int __init ess710_pci_init(void) +{ + if (machine_is_ess710()) + pci_common_init(&ess710_pci); + return 0; +} + +subsys_initcall(ess710_pci_init); + diff --git a/arch/arm/mach-ixp4xx/sg-setup.c b/arch/arm/mach-ixp4xx/sg-setup.c new file mode 100644 index 00000000..58cda930 --- /dev/null +++ b/arch/arm/mach-ixp4xx/sg-setup.c @@ -0,0 +1,253 @@ +/* + * arch/arm/mach-ixp4xx/sg-setup.c + * + * SnapGear/Cyberguard board-setup + * + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * Copyright (C) 2004-2006 Greg Ungerer + * + * Original Author: Deepak Saxena + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ARMEB__ +#define REG_OFFSET 3 +#else +#define REG_OFFSET 0 +#endif + +extern void ixp4xx_map_io(void); +extern void ixp4xx_init_irq(void); + +/* + * Console serial port (always the high speed serial port) + */ +static struct resource sg_uart_resources[] = { + { + .start = IXP4XX_UART1_BASE_PHYS, + .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM + }, + { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM + } +}; + +static struct plat_serial8250_port sg_uart_data[] = { + { + .mapbase = (IXP4XX_UART1_BASE_PHYS), + .membase = (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET), + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL + }, + { + .mapbase = (IXP4XX_UART2_BASE_PHYS), + .membase = (char*)(IXP4XX_UART2_BASE_VIRT + REG_OFFSET), + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL + }, + { }, +}; + +static struct platform_device sg_uart = { + .name = "serial8250", + .id = 0, + .dev.platform_data = sg_uart_data, + .num_resources = 2, + .resource = sg_uart_resources +}; + +void __init sg_map_io(void) +{ + ixp4xx_map_io(); +} + +static struct platform_device *sg_devices[] __initdata = { + &sg_uart +}; + +static void __init sg_init(void) +{ + ixp4xx_sys_init(); + platform_add_devices(sg_devices, ARRAY_SIZE(sg_devices)); +} + +#ifdef CONFIG_ARCH_SE4000 +MACHINE_START(SE4000, "SnapGear SE4000") + /* Maintainer: SnapGear Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG640) || defined(CONFIG_MACH_SGARMAUTO) +MACHINE_START(SG640, "SecureComputing SG640") + /* Maintainer: Secure Computing Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SGARMAUTO) +MACHINE_START(SG560, "CyberGuard SG560") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SGARMAUTO) +MACHINE_START(SG565, "CyberGuard SG565") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG580) || defined(CONFIG_MACH_SGARMAUTO) +MACHINE_START(SG580, "CyberGuard SG580") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG590) || defined(CONFIG_MACH_SGARMAUTO) +MACHINE_START(SG590, "Secure Computing SG590") + /* Maintainer: Secure Computing Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_SE5100 +MACHINE_START(SE5100, "CyberGuard SE5100") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_ESS710 +/* + * Hard set the ESS710 memory size to be 128M. Early boot loaders + * passed in 64MB in their boot tags, but now we really can use the + * 128M that the hardware has. + */ + +static void __init +ess710_fixup( + struct machine_desc *mdesc, + struct tag *tags, + char **cmdline, + struct meminfo *mi) +{ + struct tag *t = tags; + + for (; t->hdr.size; t = tag_next(t)) { + if (t->hdr.tag == ATAG_MEM) { + printk("ESS710: fixing memory size from %dMiB to 128MiB\n", + t->u.mem.size / (1024 * 1024)); + t->u.mem.start = PHYS_OFFSET; + t->u.mem.size = (128*1024*1024); + break; + } + } +} + +MACHINE_START(ESS710, "CyberGuard SG710") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .fixup = ess710_fixup, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#if defined(CONFIG_MACH_SG720) +MACHINE_START(SG720, "Secure Computing SG720") + /* Maintainer: Cyberguard Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_SG8100 +MACHINE_START(SG8100, "Secure Computing SG8100") + /* Maintainer: Secure Computing Inc. */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = sg_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x100, + .init_machine = sg_init, +MACHINE_END +#endif + diff --git a/arch/arm/mach-ixp4xx/sg5xx-pci.c b/arch/arm/mach-ixp4xx/sg5xx-pci.c new file mode 100644 index 00000000..7da39ee9 --- /dev/null +++ b/arch/arm/mach-ixp4xx/sg5xx-pci.c @@ -0,0 +1,59 @@ +/* + * arch/arch/mach-ixp4xx/sg5xx-pci.c + * + * PCI setup routines for Cyberguard/SnapGear SG5XX family boards + * + * Copyright (C) 2005 SnapGear Inc + * Copyright (C) 2004 MontaVista Softwrae, Inc. + * + * Maintainer: Cyberguard Inc + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +extern void ixp4xx_pci_preinit(void); +extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); +extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys); + +void __init sg5xx_pci_preinit(void) +{ + set_irq_type(IRQ_IXP4XX_GPIO8, IRQT_LOW); + ixp4xx_pci_preinit(); +} + +static int __init sg5xx_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot == 12 || slot == 14) + return IRQ_IXP4XX_GPIO8; + return -1; +} + +struct hw_pci sg5xx_pci __initdata = { + .nr_controllers = 1, + .preinit = sg5xx_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = sg5xx_map_irq, +}; + +int __init sg5xx_pci_init(void) +{ + if (machine_is_sg565() || machine_is_sg8100()) + pci_common_init(&sg5xx_pci); + return 0; +} + +subsys_initcall(sg5xx_pci_init); diff --git a/arch/arm/mach-ixp4xx/sg720-pci.c b/arch/arm/mach-ixp4xx/sg720-pci.c new file mode 100644 index 00000000..bed32ec0 --- /dev/null +++ b/arch/arm/mach-ixp4xx/sg720-pci.c @@ -0,0 +1,98 @@ +/* + * arch/arm/mach-ixp4xx/sg720-pci.c + * + * SG590/SG720 board-level PCI initialization + * Copyright (C) 2004-2006 SnapGear - A division of Secure Computing + * + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +void __init sg720_pci_preinit(void) +{ + /* + * Check the stepping of the IXP465 CPU. If it is not A0 or A1 then + * enable the MPI port for direct memory bus access. Much faster. + * This is broken on older steppings, so don't enable. + */ + if (cpu_is_ixp46x()) { + unsigned long processor_id; + asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); + if ((processor_id & 0xf) >= 2) { + printk("MPI: enabling fast memory bus...\n"); + *IXP4XX_EXP_CFG1 |= 0x80000000; + } else { + printk("MPI: disabling fast memory bus...\n"); + *IXP4XX_EXP_CFG1 &= ~0x80000000; + } + } + + printk("PCI: reset bus...\n"); + gpio_line_set(13, 0); + gpio_line_config(13, IXP4XX_GPIO_OUT); + gpio_line_set(13, 0); + mdelay(50); + gpio_line_set(13, 1); + mdelay(50); + + gpio_line_config(8, IXP4XX_GPIO_IN); + set_irq_type(IRQ_IXP4XX_GPIO8, IRQT_LOW); /* INTA */ + gpio_line_config(9, IXP4XX_GPIO_IN); + set_irq_type(IRQ_IXP4XX_GPIO9, IRQT_LOW); /* INTB */ + + ixp4xx_pci_preinit(); +} + +static int __init sg720_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ +#if defined(CONFIG_MACH_SG590) + if (slot == 12) + return IRQ_SG590_PCI_INTA; + else if (slot == 13) + return IRQ_SG590_PCI_INTA; +#elif defined(CONFIG_MACH_SG720) + if (slot == 12) + return IRQ_SG720_PCI_INTB; + else if (slot == 13) + return IRQ_SG720_PCI_INTB; + else if (slot == 14) + return IRQ_SG720_PCI_INTA; + else if (slot == 15) + return IRQ_SG720_PCI_INTA; +#endif + return -1; +} + +struct hw_pci sg720_pci __initdata = { + .nr_controllers = 1, + .preinit = sg720_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = sg720_map_irq, +}; + +int __init sg720_pci_init(void) +{ + if (machine_is_sg720() || machine_is_sg590()) + pci_common_init(&sg720_pci); + return 0; +} + +subsys_initcall(sg720_pci_init); + diff --git a/arch/arm/mach-ks8695/Kconfig b/arch/arm/mach-ks8695/Kconfig new file mode 100644 index 00000000..e8555cf3 --- /dev/null +++ b/arch/arm/mach-ks8695/Kconfig @@ -0,0 +1,55 @@ + +menu "Kendin-Micrel KS8695 Implementation Options" + depends on ARCH_KS8695 + +comment "KS8695 Platforms" + +config MACH_KS8695 + bool "KS8695 development board" + help + Say 'Y' here if you want your kernel to run on the original + Kendin-Micrel KS8695 development board. + +config MACH_DSM320 + bool "DLink DSM320 Media Player" + help + Say 'Y' here if you want your kernel to run on the DLink DSM320 + Media Player. + +config MACH_CM4002 + bool "OpenGear CM4002" + help + Say 'Y' here if you want your kernel to support the OpenGear + CM4002 Secure Access Server. See http://www.opengear.com for + more details. + +config MACH_CM4008 + bool "OpenGear CM4008" + help + Say 'Y' here if you want your kernel to support the OpenGear + CM4008 Console Server. See http://www.opengear.com for more + details. + +config MACH_CM40xx + bool "OpenGear CM40xx" + help + Say 'Y' here if you want your kernel to support the OpenGear + CM4016 or CM4048 Console Servers. See http://www.opengear.com for + more details. + +config MACH_LITE300 + bool "Secure Computing / CyberGuard SG300" + help + Say 'Y' here if you want your kernel to support the Secure + Computing / CyberGuard / SnapGear SG300 VPN Internet Router. + See http://www.securecomputing.com for more details. + +config MACH_SE4200 + bool "Secure Computing / CyberGuard SE4200" + help + Say 'Y' here if you want your kernel to support the Secure + Computing / CyberGuard / SnapGear SE4200 Secure Wireless VPN + Internet Router. See http://www.securecomputing.com for more + details. + +endmenu diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile new file mode 100644 index 00000000..7409348b --- /dev/null +++ b/arch/arm/mach-ks8695/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the KS8695 machines.. +# + +obj-y := arch.o irq.o mm.o time.o +obj-$(CONFIG_PCI) += pci.o + diff --git a/arch/arm/mach-ks8695/Makefile.boot b/arch/arm/mach-ks8695/Makefile.boot new file mode 100644 index 00000000..d84c5807 --- /dev/null +++ b/arch/arm/mach-ks8695/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 + diff --git a/arch/arm/mach-ks8695/arch.c b/arch/arm/mach-ks8695/arch.c new file mode 100644 index 00000000..a91fd36e --- /dev/null +++ b/arch/arm/mach-ks8695/arch.c @@ -0,0 +1,117 @@ +/* + * linux/arch/arm/mach-ks8695/arch.c + * + * Copyright (C) 2002 Micrel 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. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +extern void ks8695_map_io(void); +extern void ks8695_init_irq(void); +extern struct sys_timer ks8695_timer; + +#ifdef CONFIG_MACH_KS8695 +MACHINE_START(KS8695, "Micrel-KS8695") + /* Micrel Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_DSM320 +MACHINE_START(DSM320, "DLink-DSM320") + /* Maintainer: Ben Dooks */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT) >> 18) & 0xfffc, + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_LITE300 +MACHINE_START(KS8695, "Secure Computing SG300") + /* Secure Computing Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_SE4200 +MACHINE_START(KS8695, "Secure Computing SE4200") + /* Secure Computing Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_CM4002 +MACHINE_START(KS8695, "OpenGear/CM4002") + /* OpenGear Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_CM4008 +MACHINE_START(KS8695, "OpenGear/CM4008") + /* OpenGear Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_CM41xx +MACHINE_START(KS8695, "OpenGear/CM41xx") + /* OpenGear Inc. */ + .phys_io = KS8695_IO_BASE, + .io_pg_offst = ((KS8695_IO_VIRT >> 18) & 0xfffc), + .map_io = ks8695_map_io, + .init_irq = ks8695_init_irq, + .timer = &ks8695_timer, + .boot_params = 0x100, +MACHINE_END +#endif + diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c new file mode 100644 index 00000000..effa87c8 --- /dev/null +++ b/arch/arm/mach-ks8695/irq.c @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-ks8695/irq.c + * + * Copyright (C) 2002 Micrel Inc. + * Copyright (C) 2006 Greg Ungerer + * + * 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 +#include +#include +#include +#include +#include + +static void ks8695_irq_mask(unsigned int irq) +{ + unsigned long msk; + msk = __raw_readl(KS8695_REG(KS8695_INT_ENABLE)); + msk &= ~(1 << irq); + __raw_writel(msk, KS8695_REG(KS8695_INT_ENABLE)); +} + +static void ks8695_irq_unmask(unsigned int irq) +{ + unsigned long msk; + msk = __raw_readl(KS8695_REG(KS8695_INT_ENABLE)); + msk |= (1 << irq); + __raw_writel(msk, KS8695_REG(KS8695_INT_ENABLE)); +} + +static int ks8695_irq_set_type(unsigned int irq, unsigned int type) +{ + return 0; +} + +struct irqchip ks8695_irq_chip = { + .ack = ks8695_irq_mask, + .mask = ks8695_irq_mask, + .unmask = ks8695_irq_unmask, + .set_type = ks8695_irq_set_type, +}; + +void __init ks8695_init_irq(void) +{ + unsigned int i; + + /* Disable all interrupts initially. */ + __raw_writel(0, KS8695_REG(KS8695_INT_CONTL)); + __raw_writel(0, KS8695_REG(KS8695_INT_ENABLE)); + + for (i = 0; (i < NR_IRQS); i++) { + set_irq_chip(i, &ks8695_irq_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID); + } +} + diff --git a/arch/arm/mach-ks8695/mm.c b/arch/arm/mach-ks8695/mm.c new file mode 100644 index 00000000..eb970441 --- /dev/null +++ b/arch/arm/mach-ks8695/mm.c @@ -0,0 +1,50 @@ +/* + * linux/arch/arm/mach-ks8695/mm.c + * + * Copyright (C) 1999,2000 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 + */ + +#include +#include +#include +#include +#include +#include + +/* + * The only fixed mapping we setup is for the internal register block. + * This contains the all the device peripheral registers. + * + * Logical Physical Comment + * ----------------------------------------- + * FF000000 03FF0000 IO registers + */ +static struct map_desc ks8695_io_desc[] __initdata = { + { + .virtual = KS8695_IO_VIRT, + .pfn = __phys_to_pfn(KS8695_IO_BASE), + .length = SZ_64K, + .type = MT_DEVICE + }, +}; + +void __init ks8695_map_io(void) +{ + iotable_init(ks8695_io_desc, ARRAY_SIZE(ks8695_io_desc)); +} + diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c new file mode 100644 index 00000000..4f76a7ed --- /dev/null +++ b/arch/arm/mach-ks8695/pci.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2003, Micrel Semiconductors + * Copyright (C) 2006, Greg Ungerer + * + * Written 2003 by LIQUN RUAN + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +static u32 pcicmd(unsigned int bus, unsigned int devfn, int where) +{ + where &= 0xfffffffc; + return (0x80000000 | (bus << 16) | (devfn << 8) | where); +} + +static void local_write_config(unsigned int bus, unsigned int devfn, int where, u32 value) +{ + __raw_writel(pcicmd(bus, devfn, where), KS8695_REG(KS8695_PBCA)); + __raw_writel(value, KS8695_REG(KS8695_PBCD)); +} + + +static int ks8695_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + u32 v; + + + __raw_writel(pcicmd(bus->number, devfn, where), KS8695_REG(KS8695_PBCA)); + v = __raw_readl(KS8695_REG(KS8695_PBCD)); + + if (size == 1) + *value = (u8) (v >> ((where & 0x3) * 8)); + else if (size == 2) + *value = (u16) (v >> ((where & 0x2) * 8)); + else + *value = v; + + return PCIBIOS_SUCCESSFUL; +} + +static u32 bytemasks[] = { + 0xffffff00, 0xffff00ff, 0xff0ffff, 0x00ffffff, +}; +static u32 wordmasks[] = { + 0xffff0000, 0x00000000, 0x0000ffff, +}; + +static int ks8695_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + u32 cmd, v; + int nr; + + v = value; + cmd = pcicmd(bus->number, devfn, where); + __raw_writel(cmd, KS8695_REG(KS8695_PBCA)); + + if (size == 1) { + nr = where & 0x3; + v = __raw_readl(KS8695_REG(KS8695_PBCD)); + v = (v & bytemasks[nr]) | ((value & 0xff) << (nr * 8)); + } else if (size == 2) { + nr = where & 0x2; + v = __raw_readl(KS8695_REG(KS8695_PBCD)); + v = (v & wordmasks[nr]) | ((value & 0xffff) << (nr * 8)); + } + + __raw_writel(v, KS8695_REG(KS8695_PBCD)); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops ks8695_pci_ops = { + .read = ks8695_pci_read_config, + .write = ks8695_pci_write_config, +}; + +static struct pci_bus *ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys); +} + +static struct resource pci_mem = { + .name = "PCI memory space", + .start = KS8695P_PCI_MEM_BASE + 0x04000000, + .end = KS8695P_PCI_MEM_BASE + KS8695P_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource pci_io = { + .name = "PCI IO space", + .start = KS8695P_PCI_IO_BASE, + .end = KS8695P_PCI_IO_BASE + KS8695P_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO, +}; + +static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys) +{ + if (nr > 0) + return 0; + + /* Assign and enable processor bridge */ + local_write_config(0, 0, PCI_BASE_ADDRESS_0, KS8695P_PCI_MEM_BASE); + local_write_config(0, 0, PCI_COMMAND, + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + + request_resource(&iomem_resource, &pci_mem); + request_resource(&ioport_resource, &pci_io); + + sys->resource[0] = &pci_io; + sys->resource[1] = &pci_mem; + sys->resource[2] = NULL; + + return 1; +} + +/* + * EXT0 is used as PCI bus interrupt source. + * level detection (active low) + */ +static void __init ks8695_pci_configure_interrupt(void) +{ + u32 v; + + v = __raw_readl(KS8695_REG(KS8695_GPIO_MODE)); + v |= 0x00000001; + __raw_writel(v, KS8695_REG(KS8695_GPIO_MODE)); + + v = __raw_readl(KS8695_REG(KS8695_GPIO_CTRL)); + v &= 0xfffffff8; + v |= 0x8; + __raw_writel(v, KS8695_REG(KS8695_GPIO_CTRL)); + + v = __raw_readl(KS8695_REG(KS8695_GPIO_MODE)); + v &= ~0x00000001; + __raw_writel(v, KS8695_REG(KS8695_GPIO_MODE)); +} + +static void __init ks8695_pci_preinit(void) +{ +#if defined(CONFIG_MACH_CM4008) || defined(CONFIG_MACH_CM41xx) + /* Reset the PCI bus - (GPIO line is hooked up to bus reset) */ + u32 msk; + msk = __raw_readl(KS8695_REG(KS8695_GPIO_MODE)); + __raw_writel(msk | 0x2, KS8695_REG(KS8695_GPIO_MODE)); + + msk = __raw_readl(KS8695_REG(KS8695_GPIO_DATA)); + __raw_writel(msk & ~0x2, KS8695_REG(KS8695_GPIO_DATA)); + udelay(1000); + __raw_writel(msk | 0x2, KS8695_REG(KS8695_GPIO_DATA)); + udelay(1000); +#endif + + /* stage 1 initialization, subid, subdevice = 0x0001 */ + __raw_writel(0x00010001, KS8695_REG(KS8695_CRCSID)); + + /* stage 2 initialization */ + /* prefetch limits with 16 words, retru enable */ + __raw_writel(0x40000000, KS8695_REG(KS8695_PBCS)); + + /* configure memory mapping */ + __raw_writel(KS8695P_PCIBG_MEM_BASE, KS8695_REG(KS8695_PMBA)); + __raw_writel(KS8695P_PCI_MEM_MASK, KS8695_REG(KS8695_PMBAM)); + __raw_writel(KS8695P_PCI_MEM_BASE, KS8695_REG(KS8695_PMBAT)); + + /* configure IO mapping */ + __raw_writel(KS8695P_PCIBG_IO_BASE, KS8695_REG(KS8695_PIOBA)); + __raw_writel(KS8695P_PCI_IO_MASK, KS8695_REG(KS8695_PIOBAM)); + __raw_writel(KS8695P_PCI_IO_BASE, KS8695_REG(KS8695_PIOBAT)); + + ks8695_pci_configure_interrupt(); +} + +static int __init ks8695_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return 2; +} + +struct hw_pci ks8695_pci __initdata = { + .nr_controllers = 1, + .preinit = ks8695_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ks8695_pci_setup, + .scan = ks8695_pci_scan_bus, + .map_irq = ks8695_pci_map_irq, +}; + +static int __init ks8695_pci_init(void) +{ + pci_common_init(&ks8695_pci); + return 0; +} + +subsys_initcall(ks8695_pci_init); + diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c new file mode 100644 index 00000000..004df2b0 --- /dev/null +++ b/arch/arm/mach-ks8695/time.c @@ -0,0 +1,79 @@ +/* + * linux/arch/arm/mach-ks8695/time.c + * + * Copyright (C) 2002 Micrel Inc. + * Copyright (C) 2006 Greg Ungerer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Cannout read back time on KS8695. + */ +static unsigned long ks8695_gettimeoffset(void) +{ + return 0; +} + +static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id) +{ + write_seqlock(&xtime_lock); + __raw_writel(KS8695_INTMASK_TIMERINT1, KS8695_REG(KS8695_INT_STATUS)); + timer_tick(); + write_sequnlock(&xtime_lock); + return IRQ_HANDLED; +} + +static struct irqaction ks8695_timer_irq = { + .name = "KS8695 Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = ks8695_timer_interrupt, +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +static void __init ks8695_timer_init(void) +{ + unsigned long tmout = CLOCK_TICK_RATE / HZ / 2; + + /* Initialise to a known state (all timers off) */ + __raw_writel(0, KS8695_REG(KS8695_TIMER_CTRL)); + + /* enable timer 1 as HZ clock */ + __raw_writel(tmout, KS8695_REG(KS8695_TIMER1)); + __raw_writel(tmout, KS8695_REG(KS8695_TIMER1_PCOUNT)); + __raw_writel(0x02, KS8695_REG(KS8695_TIMER_CTRL)); + + setup_irq(KS8695_INT_TIMERINT1, &ks8695_timer_irq); +} + +struct sys_timer ks8695_timer = { + .init = ks8695_timer_init, + .offset = ks8695_gettimeoffset, +}; + diff --git a/arch/arm/mach-lpc22xx/Kconfig b/arch/arm/mach-lpc22xx/Kconfig new file mode 100644 index 00000000..92f833c9 --- /dev/null +++ b/arch/arm/mach-lpc22xx/Kconfig @@ -0,0 +1,44 @@ +# linux/arch/arm/mach-lpc22xx/Kconfig +# Copyright (C) 2004 Philips Semiconductors +# + + +menu "LPC22xx Options" + depends on ARCH_LPC22xx + +config ARCH_SUPPORTS_BIG_ENDIAN + bool "Default Big Endian mode" + default n + help + LPC22xx core supports LITTLE-ENDIAN only, + both for CPU core and the external memory access. + +config LPC22xx_Fosc + int "Oscillator Frequency" + default 10000000 + help + Oscillator frequency. The defualt is 10MHz. + Change it according to your board. + (PhyCORE HD200 Dev board(LPC22xx) use 10MHZ Oscillator) + +config ARM_CLK + int 'Arm Core Clock' + default 40000000 + help + CPU core clock frequency. The default is 40MHz. + Change it according to your application needs. + +config SKIP_DUMP_CPU_INFO + bool + default y + help + LPC22xx(ARM7TDMI) core has no cache and does not support cache size + recognition instructions which uses MMU features. + +config REMAP_VECTORS_TO_RAM + bool "Remap Vectors to ram" + default y + help + LPC22xx suppports ROM and RAM remap function. + +endmenu diff --git a/arch/arm/mach-lpc22xx/Makefile b/arch/arm/mach-lpc22xx/Makefile new file mode 100644 index 00000000..403f9a3b --- /dev/null +++ b/arch/arm/mach-lpc22xx/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o time.o +extra-y += head.o diff --git a/arch/arm/mach-lpc22xx/arch.c b/arch/arm/mach-lpc22xx/arch.c new file mode 100644 index 00000000..1648e145 --- /dev/null +++ b/arch/arm/mach-lpc22xx/arch.c @@ -0,0 +1,47 @@ +/* + * linux/arch/arm/mach-lpc22xx/arch.c + * + * Copyright (C) 2004 Philips Semiconductors + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +extern void __init lpc22xx_init_irq(void); + +extern struct sys_timer lpc22xx_timer; + +MACHINE_START(LPC22xx, "LPC22xx, PHILIPS ELECTRONICS Co., Ltd.") + MAINTAINER(" Lucy Wang ") + INITIRQ(lpc22xx_init_irq) + .timer = &lpc22xx_timer, +MACHINE_END diff --git a/arch/arm/mach-lpc22xx/head.S b/arch/arm/mach-lpc22xx/head.S new file mode 100644 index 00000000..5ea82356 --- /dev/null +++ b/arch/arm/mach-lpc22xx/head.S @@ -0,0 +1,158 @@ +/* + * linux/arch/arm/mach-lpc22xx/head.S + * + * uClinux kernel startup code for lpc22xx + * which has no proper bootloader for linux startup + * because of XIP. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + +/* Do basic initialization */ +/* Set the parameters of PLL, PINSEL, and MEMMAP carefully according to your board */ +/* These settings can be done in your bootloader instead. */ + + ldr r2,rREG_VPBDIV +#if((LPC22xx_Fcclk /4)/LPC22xx_Fpclk)==1 + mov r1,#0x0 +#endif +#if((LPC22xx_Fcclk /4)/LPC22xx_Fpclk)==2 + mov r1,#0x2 +#endif +#if((LPC22xx_Fcclk /4)/LPC22xx_Fpclk)==4 + mov r1,#0x1 +#endif + str r1,[r2] + + ldr r2,rREG_PLLCFG + +#if(LPC22xx_Fcco/LPC22xx_Fcclk/2)==1 + mov r1,#(((LPC22xx_Fcclk/CONFIG_LPC22xx_Fosc)-1)) +#endif +#if(LPC22xx_Fcco/LPC22xx_Fcclk/2)==2 + mov r1,#(((LPC22xx_Fcclk/CONFIG_LPC22xx_Fosc)-1)|(1<<5)) +#endif +#if(LPC22xx_Fcco/LPC22xx_Fcclk/2)==4 + mov r1,#(((LPC22xx_Fcclk/CONFIG_LPC22xx_Fosc)-1)|(2<<5)) +#endif +#if(LPC22xx_Fcco/LPC22xx_Fcclk/2)==8 + mov r1,#(((LPC22xx_Fcclk/CONFIG_LPC22xx_Fosc)-1)|(3<<5)) +#endif + + str r1,[r2] + + ldr r2,rREG_PLLCON + mov r1,#0x01 + str r1,[r2] + + ldr r2,rREG_PLLFEED + mov r1,#0xAA + str r1,[r2] + mov r1,#0x55 + str r1,[r2] + +1: ldr r2,rREG_PLLSTAT + ldr r1,[r2] + ands r1,r1,#0x400 + beq 1b + + ldr r2,rREG_PLLCON + mov r1,#0x03 + str r1,[r2] + + ldr r2,rREG_PLLFEED + mov r1,#0xAA + str r1,[r2] + mov r1,#0x55 + str r1,[r2] + + ldr r2,rREG_PINSEL0 + ldr r1,[r2] + and r1,r1,#~0x0f + orr r1,r1,#0x05 + str r1,[r2] + + ldr r2,rREG_MEMMAP + mov r1,#0x03 + str r1,[r2] + + b 8f + +rREG_PLLCFG: + .long REG_PLLCFG +rREG_PLLCON: + .long REG_PLLCON +rREG_PLLFEED: + .long REG_PLLFEED +rREG_VPBDIV: + .long REG_VPBDIV +rREG_PINSEL0: + .long REG_PINSEL0 +rREG_MEMMAP: + .long REG_MEMMAP +rREG_PLLSTAT: + .long REG_PLLSTAT + +VPBDIV_DAT: + .long 0x00 /* one fourth of cclk */ +PLLCFG_DAT: + .long 0x23 /* Fosc=10Mhz cclk=40Mhz*/ +PLLCON_DAT: + .long 0x03 /* PLL enable & connecte*/ + +8: + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + ldr r2, LPC22xx_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, LPC22xx_MACH_TYPE + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: + .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + + .align 8 + +LPC22xx_PROCESSOR_TYPE: + .long 0x22000000 +LPC22xx_MACH_TYPE: + .long MACH_TYPE_LPC22xx + diff --git a/arch/arm/mach-lpc22xx/irq.c b/arch/arm/mach-lpc22xx/irq.c new file mode 100644 index 00000000..77b64158 --- /dev/null +++ b/arch/arm/mach-lpc22xx/irq.c @@ -0,0 +1,137 @@ +/* + * linux/arch/arm/mach-lpc22xx/irq.c + * + * Copyright (C) 2004 Philips Semiconductors + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +void __inline__ lpc22xx_mask_irq(unsigned int irq) +{ + VICIntEnClr = 1 << irq; +} + +void __inline__ lpc22xx_unmask_irq(unsigned int irq) +{ + VICIntEnable |= 1 << irq; +} + +/* Clear pending bit */ +void __inline__ lpc22xx_clear_pb(unsigned int irq) +{ + /* write any thing to VICVectAddr */ + VICVectAddr = 0x00; + /* clear external interrupt */ + EXTINT = 0x0F; +} + +void __inline__ lpc22xx_mask_ack_irq(unsigned int irq) +{ + + lpc22xx_clear_pb(irq); + lpc22xx_mask_irq(irq); +} + + +/* YOU CAN CHANGE THIS ROUTINE FOR SPEED UP */ +__inline__ unsigned int fixup_irq (int irq ) +{ + lpc22xx_clear_pb(irq); + return(irq); +} + +static struct irqchip lpc22xx_chip = { + .ack = lpc22xx_mask_ack_irq, + .mask = lpc22xx_mask_irq, + .unmask = lpc22xx_unmask_irq, +}; + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct sysdev_class irq_class = { + set_kset_name("irq"), + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init lpc22xx_init_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &lpc22xx_chip); + set_irq_handler(irq, do_level_IRQ); + if(irq >= LPC22xx_INTERRUPT_EINT0 && irq <= LPC22xx_INTERRUPT_EINT3) + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN); + else + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* mask and disable all further interrupts */ + VICIntEnClr = 0xFFFFFFFF; + + /* set all to IRQ mode, not FIQ */ + VICIntSelect = 0x00000000; + + /* Clear Intrerrupt pending register */ + VICVectAddr = 0x00000000; + + /* Set external interrupts*/ + /* These should be different with your board */ + /* ext2: for ethernet controller rtl8019as */ + EXTMODE = 0x04; // set ext2 edge sensitive + EXTPOLAR = 0x04; // set ext2 rising edge effective + EXTINT = 0x04; // clear flags +} + diff --git a/arch/arm/mach-lpc22xx/time.c b/arch/arm/mach-lpc22xx/time.c new file mode 100644 index 00000000..0ee4dd6d --- /dev/null +++ b/arch/arm/mach-lpc22xx/time.c @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-lpc22xx/time.c + * + * Copyright (C) 2004 Philips Semiconductors + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void lpc22xx_unmask_irq(unsigned int); + +unsigned long lpc22xx_gettimeoffset (void) +{ + return (T0TC/CLOCKS_PER_USEC); +} + +static irqreturn_t +lpc22xx_timer_interrupt(int irq, void *dev_id) +{ + + if (!(T0IR & 0x01)) return IRQ_NONE; +/* do_timer(regs); + do_profile(regs); +*/ timer_tick(); /* modified 20050608 for new version */ + + T0IR |= 0x01; /* reset interrupt */ + return IRQ_HANDLED; +} + +static struct irqaction lpc22xx_timer_irq = { + .name = "LPC22xx Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = lpc22xx_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ + +void __init lpc22xx_time_init (void) +{ + /* + * disable and clear timer 0, set to + */ + T0TCR &= ~0x01; + /* initialize the timer period and prescaler */ + T0MR0 = MR0_INIT_VALUE; + T0PR = PRESCALE_COUNTER_INIT_VALUE; + T0MCR |= 0x03; /* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/ + + /* + * @todo do those really need to be function pointers ? + */ +/* gettimeoffset = lpc22xx_gettimeoffset; */ + lpc22xx_timer_irq.handler = lpc22xx_timer_interrupt; + + /* set up the interrupt vevtor for timer 0 match */ + setup_irq(LPC22xx_INTERRUPT_TIMER0, &lpc22xx_timer_irq); + + /* enable the timer IRQ */ + lpc22xx_unmask_irq(LPC22xx_INTERRUPT_TIMER0); + + /* let timer 0 run... */ + T0IR = 0x01; /* reset MR0 interrupt*/ + T0TCR = 0x02; /* Reset timer count and prescale counter */ + T0TCR = 0x01; /* enablle timer counter and prescale counter */ +} + +struct sys_timer lpc22xx_timer = { + .init = lpc22xx_time_init, + .offset = lpc22xx_gettimeoffset, +}; diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig new file mode 100644 index 00000000..fb8c8c33 --- /dev/null +++ b/arch/arm/mach-moxart/Kconfig @@ -0,0 +1,35 @@ +menu "MOXART Options" + depends on ARCH_MOXART + +config SYS_CLK + int 'SysClk' + default 192000000 + help + Set your system clock. + +config UART_CLK + int 'UartClk' + default 14745600 + help + Set your uart clock. + +config LARGE_ALLOCS + bool "Allow allocating large blocks (> 1MB) of memory" + help + Allow the slab memory allocator to keep chains for very large + memory sizes - upto 32MB. You may need this if your system has + a lot of RAM, and you need to able to allocate very large + contiguous chunks. If unsure, say N. + +config SKIP_DUMP_CPU_INFO + bool + default y + help + ARM9TDMI cores do not support cache size + recognition instructions which use MMU features. + +config ARCH_UC7110 + bool "Moxa UC7110-LX hardware platform" + depends on ARCH_MOXART + +endmenu diff --git a/arch/arm/mach-moxart/Makefile b/arch/arm/mach-moxart/Makefile new file mode 100644 index 00000000..398e9f9d --- /dev/null +++ b/arch/arm/mach-moxart/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +# Object file lists. + +obj-y := arch.o irq.o timer.o gpio.o + +obj-$(CONFIG_ARCH_UC7112) += apb_dma.o +obj-$(CONFIG_ARCH_EM1220) += apb_dma.o +obj-$(CONFIG_ARCH_EM1220_DLIN) += apb_dma.o +obj-$(CONFIG_ARCH_EM1240) += apb_dma.o +obj-$(CONFIG_ARCH_EM1240_IVTC) += apb_dma.o +obj-$(CONFIG_ARCH_EM1220_APIT) += apb_dma.o +obj-$(CONFIG_ARCH_EM1240_MT) += apb_dma.o +obj-$(CONFIG_ARCH_UC7101) += apb_dma.o +obj-$(CONFIG_ARCH_W311_TEST) += apb_dma.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/arm/mach-moxart/ahb_dma.c b/arch/arm/mach-moxart/ahb_dma.c new file mode 100644 index 00000000..975e8231 --- /dev/null +++ b/arch/arm/mach-moxart/ahb_dma.c @@ -0,0 +1,214 @@ +/* +ahb_dma.c programmed by Ivan Wang +AHB dma program for audio 2004/8/13 06:00pm +*/ +#include +#include +#include +#include +#include +#include + + +ahb_dma_data_t *ahb_dma_alloc(void) +{ + ahb_dma_data_t *priv; + priv=(ahb_dma_data_t *)kmalloc(sizeof(ahb_dma_data_t), GFP_KERNEL); + return priv; +} + +void ahb_dma_free(ahb_dma_data_t *priv) +{ + int size; + size=sizeof(ahb_lld_t)*(priv->llp_count); + if(priv->ahb_dma_lld) + { + consistent_free((void *)priv->ahb_dma_lld,size,(dma_addr_t)priv->ahb_dma_lld_phys); + //printk("free 0x%x whit 0x%x size 0x%x\n",priv->ahb_dma_lld,priv->ahb_dma_lld_phys,size); + } + ahb_dma_reset(priv); + kfree(priv); +} + +/* +You must given: + base: base address of ahb dma + llp_master: LLP master channel number + src_data_master: source data channel number + dest_data_master: dest data channel number + llp_count: LLP count + channel: ahb dma channel + hw is it hardware handshake? +*/ +int ahb_dma_init(ahb_dma_data_t *priv) +{ + int i,size; + ahb_lld_t *lld=0; + ahb_lld_t *lld_phys=0; + + if(priv==0) + { + printk("NULL priv data!\n"); + return 0; + } + + if(priv->llp_count) + { + size=sizeof(ahb_lld_t)*(priv->llp_count); + priv->ahb_dma_lld=(ahb_lld_t *)consistent_alloc(GFP_DMA|GFP_KERNEL, + size,(dma_addr_t *)&priv->ahb_dma_lld_phys); + //printk("priv->ahb_dma_lld=0x%x phys=0x%x size=0x%x\n",(int)priv->ahb_dma_lld,(int)priv->ahb_dma_lld_phys,size); + if(priv->ahb_dma_lld==0) + { + printk("ahb_dma_lld allocate memory fail!\n"); + return 0; + } + } + + priv->channel_base=(priv->base)+0x100+((priv->channel)*0x20); + priv->llp_last_idx=0; + priv->llp_free_idx=0; + priv->ahb_last_lld=0; + + lld=priv->ahb_dma_lld; + lld_phys=priv->ahb_dma_lld_phys; + /* initialize value */ + for(i=0;illp_count;i++) + { + lld[i].source=0; //source + lld[i].dest=0; //dest,16bit + lld[i].control=0; + + if(i==priv->llp_count-1) + lld[i].llp=0; + else + lld[i].llp=(unsigned int)(&lld_phys[i+1])|(priv->llp_master); //use second channel + //printk("ahb_dma_lld[%d].llp\n",i,ahb_dma_lld[i].llp); + } + + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)=0; + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CFG_0x4)=0x0; //enabled all interrupt + *(unsigned int *)(priv->base+AHBDMA_ENABLE_0x24)=0x1; //enable DMA controller + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=0; + return 1; +} + +/* +LLP count =3 (example) + 0 => 1 => 2 => 3 + ^ | + +---------+ +You must prepared: + src: source address + dest:dest address + sw: source width (0/1/2=>8/16/32) + dw: dest width (0/1/2=>8/16/32) + sctl: source control (0/1/2/3=>inc/dec/fix/x) + dctl: dest coontrol (0/1/2/3=>inc/dec/fix/x) + size: dma count + irq: (0/1)==>(disable/enable) + */ +void ahb_dma_add(ahb_dma_data_t *priv,ahb_dma_parm_t *parm) +{ + unsigned int val; + ahb_lld_t *lld; + ahb_lld_t *lld_phys; + //printk("add priv=0x%x\n",priv); + lld=priv->ahb_dma_lld; + lld_phys=priv->ahb_dma_lld_phys; + + if(priv->llp_free_idx==0) //first to call ahb_dma_add + { + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_TXSZ_0x14)=parm->size; + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_SRC_0x8)=parm->src; + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_DST_0xC)=parm->dest; + + if (priv->llp_count == 0) + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)= 0; //john modified, for no LLP + else + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)= + (unsigned int)(&lld_phys[0])|priv->llp_master; + + val=(((1-(parm->irq))<<31)&0x80000000)| + ((parm->sw<<11)&0x00003800)|((parm->dw<<8)&0x00000700)| + ((priv->hw_handshake<<7)&0x00000080)| + ((parm->sctl<<5)&0x00000060)|((parm->dctl<<3)&0x00000018)| + ((priv->src_data_master<<2)&0x4)| + ((priv->dest_data_master<<1)&0x2); + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=val; + } + else + { + val=((parm->irq<<28)&0x10000000)| + ((parm->sw<<25)&0x0e000000)|((parm->dw<<22)&0x01c00000)| + ((parm->sctl<<20)&0x00300000)|((parm->dctl<<18)&0x000c0000)| + ((priv->src_data_master<<17)&0x00020000)| + ((priv->dest_data_master<<16)&0x00010000)|(parm->size); + lld[priv->llp_free_idx-1].source=parm->src; + lld[priv->llp_free_idx-1].dest=parm->dest; + lld[priv->llp_free_idx-1].control=val; + lld[priv->llp_free_idx-1].llp=0; + + if(priv->ahb_last_lld) + priv->ahb_last_lld->llp=(unsigned int)(&lld_phys[priv->llp_free_idx-1])|priv->llp_master; + priv->ahb_last_lld=&lld[priv->llp_free_idx-1]; + } + + if (priv->llp_count) //john add check + { + if(priv->llp_free_idx==priv->llp_count) + priv->llp_free_idx=1; + else + priv->llp_free_idx++; + } +} + +inline void ahb_dma_start(ahb_dma_data_t *priv) +{ + *(volatile unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)|=0x1; +} + +void ahb_dma_reset(ahb_dma_data_t *priv) +{ + priv->llp_last_idx=0; + priv->llp_free_idx=0; + priv->ahb_last_lld=0; + + //printk("ahb_dma_stop\n"); + *(unsigned int *)(priv->base+AHBDMA_ENABLE_0x24)=0; //disable DMA controller + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CSR_0x0)=0; //disable DMA channel 0 + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_LLP_0x10)=0; + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_TXSZ_0x14)=0; //no transfer size (use LLP) + *(unsigned int *)(priv->channel_base+AHBDMA_CHANNEL_CFG_0x4)=0; //disable all interrupt +} + +inline void ahbdma_clear_int(ahb_dma_data_t *priv) +{ + *(volatile unsigned int *)(priv->base+AHBDMA_ISR_0x8)=1<<(priv->channel); +} + +//john add, get ext DMA address +// so we can get DMA lenth +inline u32 ahbdma_get_dest_addr(ahb_dma_data_t *priv) +{ + return *(volatile u32 *)(priv->channel_base+AHBDMA_CHANNEL_DST_0xC); +} + +// John add, to get interrupt status +// Bit 0 indicate interrupt created, +// bit 1 indicate interrupt error +u32 ahbdma_get_status(ahb_dma_data_t *priv) +{ + u32 status=0; + u32 temp; + + temp = *(volatile u32 *)(priv->base+AHBDMA_INT_ERR_0x0C); + if ( temp & (1<<(priv->channel)) ) + status |= INT_ERROR; //error + + temp = *(volatile u32 *)(priv->base+AHBDMA_INT_TC_0x04); + if ( temp & (1<<(priv->channel)) ) + status |= INT_TRIGGER; //complete + + return status; +} \ No newline at end of file diff --git a/arch/arm/mach-moxart/apb_dma.c b/arch/arm/mach-moxart/apb_dma.c new file mode 100644 index 00000000..b700308a --- /dev/null +++ b/arch/arm/mach-moxart/apb_dma.c @@ -0,0 +1,267 @@ + +/* + * Copyright (C) 2005 Moxa Group All Rights Reserved. + * + * History: + * Date Author Comment + * 12-01-2005 Victor Yu. Create it. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define MOXA_DEBUG +#ifdef MOXA_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static apb_dma_priv apb_dma_channel[APB_DMA_MAX_CHANNEL]; +static spinlock_t apb_dma_lock; + +apb_dma_priv *apb_dma_alloc(int req_no) +{ + int i; + unsigned long flags; + apb_dma_priv *priv=apb_dma_channel; + + spin_lock_irqsave(&apb_dma_lock, flags); + for ( i=0; iused_flag == 0 ) { + priv->used_flag = 1; + priv->irq_handler = NULL; + priv->irq_handler_param = NULL; + priv->error_flag = 0; + priv->req_no = req_no; + switch ( req_no ) { + case APB_DMA_SPI_TX_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xA0) = 0; + break; + case APB_DMA_SPI_RX_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xA4) = 0; + break; + case APB_DMA_SD_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xB8) = 0; + break; + case APB_DMA_AC97_TX_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xBC) = 0; + break; + case APB_DMA_AC97_RX_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xC0) = 0; + break; + case APB_DMA_USB_DEVICE_REQ_NO : + *(unsigned int *)(CPE_PMU_BASE+0xCC) = 0; + break; + } + spin_unlock_irqrestore(&apb_dma_lock, flags); + DBG("apb_dma_alloc uses DMA channel %d\n", i); + return priv; + } + } + spin_unlock_irqrestore(&apb_dma_lock, flags); + return NULL; +} +EXPORT_SYMBOL(apb_dma_alloc); + +void apb_dma_release(apb_dma_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&apb_dma_lock, flags); + if ( priv == NULL ) { + spin_unlock_irqrestore(&apb_dma_lock, flags); + return; + } + priv->used_flag = 0; + priv->error_flag = 0; + priv->irq_handler = NULL; + priv->irq_handler_param = NULL; + priv->req_no = 0; + spin_unlock_irqrestore(&apb_dma_lock, flags); +} +EXPORT_SYMBOL(apb_dma_release); + +void apb_dma_set_irq(apb_dma_priv *priv, void (*func)(void *param), void *param) +{ + unsigned long flags; + unsigned int cmd; + + spin_lock_irqsave(&apb_dma_lock, flags); + if ( priv == NULL ) { + spin_unlock_irqrestore(&apb_dma_lock, flags); + return; + } + priv->irq_handler = func; + priv->irq_handler_param = param; + priv->error_flag = 0; + cmd = readl(&priv->reg->command.ul); + cmd |= (APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN); + writel(cmd, &priv->reg->command.ul); + spin_unlock_irqrestore(&apb_dma_lock, flags); +} +EXPORT_SYMBOL(apb_dma_set_irq); + +void apb_dma_release_irq(apb_dma_priv *priv) +{ + unsigned long flags; + unsigned int cmd; + + spin_lock_irqsave(&apb_dma_lock, flags); + if ( priv == NULL ) { + spin_unlock_irqrestore(&apb_dma_lock, flags); + return; + } + cmd = readl(&priv->reg->command.ul); + cmd &= ~(APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN); + writel(cmd, &priv->reg->command.ul); + priv->irq_handler = NULL; + priv->irq_handler_param = NULL; + priv->error_flag = 0; + spin_unlock_irqrestore(&apb_dma_lock, flags); +} +EXPORT_SYMBOL(apb_dma_release_irq); + +void apb_dma_conf(apb_dma_priv *priv, apb_dma_conf_param *param) +{ + unsigned long flags; + union _command cmd; + unsigned int size; + + spin_lock_irqsave(&apb_dma_lock, flags); + writel(param->source_addr, &priv->reg->source_addr); + writel(param->dest_addr, &priv->reg->dest_addr); + size = param->size; + switch ( param->data_width ) { + case APB_DMAB_DATA_WIDTH_1 : + break; + case APB_DMAB_DATA_WIDTH_2 : + size >>= 1; + break; + case APB_DMAB_DATA_WIDTH_4 : + default : + size >>= 2; + break; + } + if ( param->burst_mode ) + size >>= 2; + writel(size, &priv->reg->cycles); + cmd.ul = readl(&priv->reg->command.ul); + cmd.bits.data_width = param->data_width; + if ( param->dest_sel ) { // AHB +#if 1 // add by Victor Yu. 07-12-2007 + dmac_inv_range(param->dest_addr, param->dest_addr+param->size); +#endif + cmd.bits.dest_req_no = 0; + } else { // APB + cmd.bits.dest_req_no = priv->req_no; + } + cmd.bits.dest_sel = param->dest_sel; + if ( param->source_sel ) { // AHB +#if 1 // add by Victor Yu. 07-12-2007 + dmac_flush_range(param->source_addr, param->source_addr+param->size); +#endif + cmd.bits.source_req_no = 0; + } else { // APB + cmd.bits.source_req_no = priv->req_no; + } + cmd.bits.source_sel = param->source_sel; + cmd.bits.burst = param->burst_mode; + cmd.bits.dest_inc = param->dest_inc; + cmd.bits.source_inc = param->source_inc; + writel(cmd.ul, &priv->reg->command.ul); + spin_unlock_irqrestore(&apb_dma_lock, flags); +} +EXPORT_SYMBOL(apb_dma_conf); + +void apb_dma_enable(apb_dma_priv *priv) +{ + unsigned long flags; + unsigned int cmd; + + spin_lock_irqsave(&apb_dma_lock, flags); + cmd = readl(&priv->reg->command.ul); + cmd |= APB_DMA_ENABLE; + writel(cmd, &priv->reg->command.ul); + spin_unlock_irqrestore(&apb_dma_lock, flags); +} +EXPORT_SYMBOL(apb_dma_enable); +EXPORT_SYMBOL(apb_dma_disable); +void apb_dma_disable(apb_dma_priv *priv) +{ + unsigned long flags; + unsigned int cmd; + + spin_lock_irqsave(&apb_dma_lock, flags); + cmd = readl(&priv->reg->command.ul); + cmd &= ~APB_DMA_ENABLE; + writel(cmd, &priv->reg->command.ul); + spin_unlock_irqrestore(&apb_dma_lock, flags); +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-08-2007 +static irqreturn_t apb_dma_irq(int irq, void *devid) +#else +static irqreturn_t apb_dma_irq(int irq, void *devid, struct pt_regs *regs) +#endif // LINUX_VERSION_CODE +{ + int i; + unsigned int cmd; + apb_dma_priv *priv=apb_dma_channel; + + DBG("apb_dma_irq test01\n"); + for ( i=0; ireg->command.ul); + if ( cmd & APB_DMA_FIN_INT_STS ) { + DBG("apb_dma_irq finish interrupt channel [%d]\n", i); + cmd &= ~APB_DMA_FIN_INT_STS; + } + if ( cmd & APB_DMA_ERR_INT_STS ) { + DBG("apb_dma_irq error interrupt channel [%d]\n", i); + cmd &= ~APB_DMA_ERR_INT_STS; + priv->error_flag = 1; + } + if ( priv->used_flag && priv->irq_handler ) { + priv->irq_handler(priv->irq_handler_param); + } + priv->error_flag = 0; + writel(cmd, &priv->reg->command.ul); + } + + return IRQ_HANDLED; +} + +static int __init apb_dma_init(void) +{ + int ret, i; + apb_dma_priv *priv=apb_dma_channel; + + printk("Moxa CPU APB DMA Device Driver V1.0 load "); + + memset(apb_dma_channel, 0, sizeof(apb_dma_channel)); + spin_lock_init(&apb_dma_lock); + + for ( i=0; ireg = (apb_dma_reg *)(CPE_APBDMA_BASE+0x80+i*sizeof(apb_dma_reg)); + } + + cpe_int_set_irq(IRQ_APBDMA, EDGE, H_ACTIVE); + ret = request_irq(IRQ_APBDMA, apb_dma_irq, SA_INTERRUPT, "APB DMA", NULL); + if ( ret ) + printk("fail !\n"); + else + printk("OK.\n"); + + return ret; +} + +module_init(apb_dma_init); diff --git a/arch/arm/mach-moxart/arch.c b/arch/arm/mach-moxart/arch.c new file mode 100644 index 00000000..2ff988de --- /dev/null +++ b/arch/arm/mach-moxart/arch.c @@ -0,0 +1,233 @@ +/* + * linux/arch/arm/mach-cpe/arch.c + * modified by ivan wang 2004/8/18 01:35pm + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include /*Calling moxa_timer_init*/ +#include /*Calling moxa_irq_init*/ +#include +#include +#include +#include + +#if 0 // mask by Victor Yu. 02-12-2007 +static struct uart_port moxa_serial_ports[] = { + { + .iobase = CPE_UART1_BASE, + .mapbase = CPE_UART1_BASE, + .irq = IRQ_UART, + .flags = UPF_SKIP_TEST|UPF_SHARE_IRQ, + .iotype = UPIO_PORT, + .regshift = 2, + .uartclk = CONFIG_UART_CLK, + .line = 0, + .type = PORT_16550A, + .fifosize = 16 + }, + { + .mapbase = CPE_UART2_BASE, + .iobase = CPE_UART2_BASE, + .irq = IRQ_UART, + .flags = UPF_SKIP_TEST|UPF_SHARE_IRQ, + .iotype = UPIO_PORT, + .regshift = 2, + .uartclk = CONFIG_UART_CLK, + .line = 1, + .type = PORT_16550A, + .fifosize = 16 + } +}; +#else +static struct uart_port moxa_serial_ports[2]; +#endif + +#if 0 // mask by Victor Yu. 02-08-2007 +static int __init moxa_serial_init(void) +{ + early_serial_setup(&moxa_serial_ports[0]); + early_serial_setup(&moxa_serial_ports[1]); + return 0; +} +__initcall(moxa_serial_init); +#endif + +#if 1 // add by Victor Yu, 03-15-2007 +#include +extern void cpe_mask_irq(unsigned int irq); +extern void cpe_unmask_irq(unsigned int irq); +extern void cpe_mask_ack_irq(unsigned int irq); +extern void cpe_clear_irq(unsigned int intNum); +extern void cpe_int_init(void); +static struct irqchip cpe_irq_chip; +static void irq_init_irq(void) +{ + unsigned long flags; + int irq; + + save_and_cli(flags); + cpe_int_init(); + restore_flags(flags); + cpe_irq_chip.ack = cpe_mask_ack_irq; + cpe_irq_chip.mask = cpe_mask_irq; + cpe_irq_chip.unmask = cpe_unmask_irq; + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &cpe_irq_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } +} +#endif + +static void __init +fixup_uc711x(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = CONFIG_DRAM_BASE; + mi->bank[0].size = CONFIG_DRAM_SIZE; + mi->bank[0].node = 0; + +#if 1 // add by Victor Yu. 02-12-2007 + moxa_serial_ports[0].iobase = CPE_UART1_BASE; + moxa_serial_ports[0].mapbase = CPE_UART1_BASE; + moxa_serial_ports[0].irq = IRQ_UART; + moxa_serial_ports[0].flags = UPF_SKIP_TEST|UPF_SHARE_IRQ; + moxa_serial_ports[0].iotype = UPIO_PORT; + moxa_serial_ports[0].regshift = 2; + moxa_serial_ports[0].uartclk = CONFIG_UART_CLK; + moxa_serial_ports[0].line = 0; + moxa_serial_ports[0].type = PORT_16550A; + moxa_serial_ports[0].fifosize = 16; + + moxa_serial_ports[1].iobase = CPE_UART2_BASE; + moxa_serial_ports[1].mapbase = CPE_UART2_BASE; + moxa_serial_ports[1].irq = IRQ_UART; + moxa_serial_ports[1].flags = UPF_SKIP_TEST|UPF_SHARE_IRQ; + moxa_serial_ports[1].iotype = UPIO_PORT; + moxa_serial_ports[1].regshift = 2; + moxa_serial_ports[1].uartclk = CONFIG_UART_CLK; + moxa_serial_ports[1].line = 1; + moxa_serial_ports[1].type = PORT_16550A; + moxa_serial_ports[1].fifosize = 16; + + early_serial_setup(&moxa_serial_ports[0]); + early_serial_setup(&moxa_serial_ports[1]); +#endif +} + +extern struct sys_timer moxa_timer; + +#ifdef CONFIG_ARCH_UC7110 +MACHINE_START(MOXART, "UC7110") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_UC7112 +MACHINE_START(MOXART, "UC7112") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1220 +MACHINE_START(MOXART, "EM1220") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1220_DLIN +MACHINE_START(MOXART, "EM1220 DLIN") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1220_APIT +MACHINE_START(MOXART, "EM1220 APIT") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1240 +MACHINE_START(MOXART, "EM1240") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1240_IVTC +MACHINE_START(MOXART, "EM1240 IVTC") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1240_MT +MACHINE_START(MOXART, "EM1240 MT") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_W321_GL2 +MACHINE_START(MOXART, "W321 GL2") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_W315_EC +MACHINE_START(MOXART, "W315_EC") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_UC7101 +MACHINE_START(MOXART, "UC7101") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_W311_TEST +MACHINE_START(MOXART, "W311_TEST") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_ARCH_EM1110 +MACHINE_START(MOXART, "EM1110") + .fixup = fixup_uc711x, + .init_irq = irq_init_irq, + .timer = &moxa_timer, +MACHINE_END +#endif diff --git a/arch/arm/mach-moxart/cpe_dma.c b/arch/arm/mach-moxart/cpe_dma.c new file mode 100644 index 00000000..6af303e9 --- /dev/null +++ b/arch/arm/mach-moxart/cpe_dma.c @@ -0,0 +1,253 @@ +/*************************************************************************** +* Copyright Faraday Technology Corp 2002-2003. All rights reserved. * +*--------------------------------------------------------------------------* +* Name:SD_CNTR.c * +* Description: SD relative routines * +* Author: Ted Hsu * +**************************************************************************** +* Porting to Linux on 20030526 * +* Author: Paul Chiang * +* Version: 0.1 * +* History: * +* 0.1 new creation * +* 0.2 Porting to meet the style of linux dma * +* Todo: * +****************************************************************************/ +#define __NO_VERSION__ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "dma.h" + +//#define P_DEBUG(a...) printk("<0> CPE_DMA:" ##a) +#define P_DEBUG(a...) + +#ifdef CONFIG_UCLINUX // uclinux without mmu +// #error "CONFIG_UCLINUX" + #define OUTW(port,value) outl(value,port) + #define INW(port) inl(port) + #define REQUEST_IO_REGION(a,b,c) request_region(a,b,c) + #define CPUCleanInvalidateDCacheAll() +#else //arm linux with mmu + + #define OUTW(port,value) outl(value,(IO_ADDRESS((port)))) + #define INW(port) inl((IO_ADDRESS((port)))) + #define REQUEST_IO_REGION(a,b,c) request_region((IO_ADDRESS((a))),b,c) + #define CPUCleanInvalidateDCacheAll() +#endif + +#define CPE_MAX_DMA_CHANNELS (CPE_APB_DMA_MAX_CHANNEL+CPE_AHB_DMA_MAX_CHANNEL) +extern dma_t fapb_dma_chan[CPE_MAX_DMA_CHANNELS]; //paulong 20030616 remove static +//======================================================================== +struct dma_record +{ + uint active; //dma is working + uint base_addr; + dma_handler_func_t dma_handler; //(int irq,uint finish_status,uint error_status) paul 20030617 + uint int_nr; +}; +static struct dma_record DMA_INTR[CPE_MAX_DMA_CHANNELS]; + +//=============================================== +void APB_set_dma_intr (dmach_t channel, dma_handler_func_t func) +{ + DMA_INTR[channel].dma_handler = func; // paul 20030617 +} + +//--------------------------------- +static void APB_enable_dma(dmach_t channel, dma_t * dma) +{ + P_DEBUG("APB_enable_dma()\n"); + DMA_INTR[channel].active = 1; + fLib_APBDMA_Interrupt( dma->dma_base, 1, 1); + fLib_APBDMA_EnableTrans(dma->dma_base, 1); + //CPUCleanInvalidateDCacheAll (); // mark by Charles Tsai +} + +//--------------------------------- +static void APB_disable_dma (dmach_t channel, dma_t * dma) +{ + P_DEBUG ("APB_disable_dma()\n"); + DMA_INTR[channel].active = 0; + //fLib_APBDMA_Interrupt( dma->dma_base, 0, 0); //move to init_cpe_dma() run once + fLib_APBDMA_EnableTrans (dma->dma_base, 0); +} + +//--------------------------------- +static struct dma_ops APB_dma_ops = { + enable: APB_enable_dma, + disable: APB_disable_dma, + type: "APB_DMA ", +}; +//--------------------------------- +#define loop_APB_dma_channel() for (i = 0; i < CPE_APB_DMA_MAX_CHANNEL; i++) +#define loop_AHB_dma_channel() for (i = 0; i < CPE_AHB_DMA_MAX_CHANNEL; i++) +#define loop_all_dma_channel() for (i = 0; i < CPE_MAX_DMA_CHANNELS; ++i) +//----------------------------------------------- +#ifdef P_DEBUG +void Dumpdma (void) +{ + int i; + dma_t *dma = fapb_dma_chan; + + printk ("Dma Channel Informations---\n"); + loop_all_dma_channel () + { + printk (" Channel=%d:\n", i); + //...........APB DMA Channels + if (i < CPE_APB_DMA_MAX_CHANNEL) //Paul: 0~3 APB, 4~12 AHB + { + printk (" APB--"); + } + //...........AHB DMA Channels + else + { + printk (" AHB--"); + } + + printk ("active=%d,", dma[i].active); + printk ("invalid=%d,", dma[i].invalid); + printk ("using_sg=%d,", dma[i].using_sg); + printk ("dma_mode=%d,", dma[i].dma_mode); + printk ("speed=%d,", dma[i].speed); + printk ("lock=0x%X,", dma[i].lock); + printk ("device_id=%s,", dma[i].device_id); + printk ("dma_base=0x%X,", dma[i].dma_base); + printk ("dma_irq=%d,", dma[i].dma_irq); + printk ("state=%d,", dma[i].state); + printk ("d_ops=0x%lX\n",(ulong) dma[i].d_ops); + } +} +#endif + +//-------------------------------- +void AHB_interrupt_handler (int irq, void *dev_id, struct pt_regs *dummy) +{ + P_DEBUG ("AHB_interrupt_handler()\n"); + P_DEBUG ("irq=0x%X 1\n", irq); +} + +//------------------- +int APB_Check_Finish_DMA(dmach_t channel) +{ + + return (DMA_INTR[channel].active==0); // return 1 finished, return 0 unfinished +} + +//----------------- +void APB_interrupt_handler(int irq, void *dev_id, struct pt_regs *dummy) +{ + uint i; + uint FinishStatus, ErrorStatus; + + //DMA_INTR[0].dma_handler(irq,1,0); /* special process by Charles tsai */ + //return; + P_DEBUG("APB_interrupt_handler()\n"); + P_DEBUG("irq=0x%X 1\n", irq); + + loop_APB_dma_channel() { + FinishStatus = fLib_APBDMA_ChkFinish(DMA_INTR[i].base_addr); + ErrorStatus = fLib_APBDMA_ChkErr(DMA_INTR[i].base_addr); + if (FinishStatus || ErrorStatus) { + DMA_INTR[i].active = 0; + fLib_APBDMA_ClrStatus(DMA_INTR[i].base_addr); //paul 20030617 + if (DMA_INTR[i].dma_handler != NULL) { + //dma_isr=(dma_handler_func_t)DMA_INTR[i].dma_handler; + //(*dma_isr)(irq,FinishStatus,ErrorStatus); //dispatch + DMA_INTR[i].dma_handler(irq, FinishStatus, ErrorStatus); + } else + printk("APB dma (channels=%d) irq=%d occur, but isr is NULL\n", i, irq); + } + } +} + +//--------------------------------- +void __init arch_dma_init (dma_t * dma) +{ + //init_cpe_dma() cannot request irq /io here, execute later +} + +//-------------------------------------- +int __init init_cpe_dma(void) +{ + int i, result; + dma_t *dma = fapb_dma_chan; + + printk("Faraday CPE DMA drivers, %d channels\n", CPE_MAX_DMA_CHANNELS); + + loop_all_dma_channel() { + //............ APB DMA Channels + if (i < CPE_APB_DMA_MAX_CHANNEL) { //Paul: 0~3 APB, 4~12 AHB + dma[i].d_ops = &APB_dma_ops; + dma[i].dma_irq = IRQ_APB_BRIDGE; // waiting to do: + + switch (i) { + case 0: + dma[i].dma_base = AHB2APB_DMA_A; + REQUEST_IO_REGION(dma[i].dma_base, 0x10, "AHB2APB_DMA_A"); + break; + case 1: + dma[i].dma_base = AHB2APB_DMA_B; + REQUEST_IO_REGION(dma[i].dma_base, 0x10, "AHB2APB_DMA_B"); + break; + case 2: + dma[i].dma_base = AHB2APB_DMA_C; + REQUEST_IO_REGION(dma[i].dma_base, 0x10, "AHB2APB_DMA_C"); + break; + case 3: + dma[i].dma_base = AHB2APB_DMA_D; + REQUEST_IO_REGION(dma[i].dma_base, 0x10, "AHB2APB_DMA_D"); + break; + } + + if (i == 0) { // do once + cpe_int_set_irq(dma[i].dma_irq, EDGE, H_ACTIVE); + result = request_irq(dma[i].dma_irq, APB_interrupt_handler, SA_INTERRUPT, "APB DMA controller", NULL); + if (result != 0) { + printk(" APB Dma drivers, %d channels, intr=%d....Failed\n", CPE_APB_DMA_MAX_CHANNEL, dma[i].dma_irq); + return -1; + } else + printk(" APB Dma drivers, %d channels, intr=%d\n",CPE_APB_DMA_MAX_CHANNEL, dma[i].dma_irq); + } + } +#if 0 /* chris lee removed */ + //............ AHB DMA Channels + else //Paul: not implement + { + dma[i].d_ops = NULL; + dma[i].dma_base = 0; + dma[i].dma_irq = FIQ_DMA; + if (i == CPE_APB_DMA_MAX_CHANNEL) { + printk(" AHB Dma drivers, %X channels, intr=%d\n", CPE_AHB_DMA_MAX_CHANNEL, dma[i].dma_irq); + } + } +#endif + //................general + dma[i].active = 0; + dma[i].invalid = 1; + dma[i].using_sg = 0; + + DMA_INTR[i].base_addr = dma[i].dma_base; + DMA_INTR[i].dma_handler = NULL; + DMA_INTR[i].int_nr = dma[i].dma_irq; + DMA_INTR[i].active = 0; + } + + return 1; +} + +EXPORT_SYMBOL(APB_Check_Finish_DMA); +module_init (init_cpe_dma); diff --git a/arch/arm/mach-moxart/debug.c b/arch/arm/mach-moxart/debug.c new file mode 100644 index 00000000..f801555a --- /dev/null +++ b/arch/arm/mach-moxart/debug.c @@ -0,0 +1,34 @@ + +#include + +#define SERIAL_THR 0x00 +#define SERIAL_LSR 0x14 +#define SERIAL_LSR_THRE 0x20 + +void debug_puts(const char *s) +{ + while (*s) + { + volatile unsigned int status=0; + do + { + status = *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_THR) = *s; + + if (*s == '\n') + { + + do + { + status = *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_THR) = '\r'; + } + s++; + } +} diff --git a/arch/arm/mach-moxart/debug_cpe.c b/arch/arm/mach-moxart/debug_cpe.c new file mode 100644 index 00000000..8f731960 --- /dev/null +++ b/arch/arm/mach-moxart/debug_cpe.c @@ -0,0 +1,55 @@ +/* + * linux/include/asm-arm/arch-integrator/debug-cpe.c + * + * Copyright (C) 1999 ARM Limited + * + * 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 + +#define SERIAL_THR 0x00 +#define SERIAL_LSR 0x14 +#define SERIAL_LSR_THRE 0x20 + +void debug_puts(const char *s) +{ + while (*s) + { + volatile unsigned int status=0; + do + { + status = *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_THR) = *s; + + if (*s == '\n') + { + + do + { + status = *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(IO_ADDRESS(CPE_UART1_BASE)+SERIAL_THR) = '\r'; + } + s++; + } +// while (AMBA_UART_FR & (1 << 3)); +} + diff --git a/arch/arm/mach-moxart/dma.h b/arch/arm/mach-moxart/dma.h new file mode 100644 index 00000000..e22dace9 --- /dev/null +++ b/arch/arm/mach-moxart/dma.h @@ -0,0 +1,197 @@ +#ifndef ARCH_CPE_RTC_H +#define ARCH_CPE_RTC_H + + /* registers */ +#define DMA_INT 0x0 +#define DMA_INT_TC 0x4 +#define DMA_INT_TC_CLR 0x8 +#define DMA_INT_ERR 0xC +#define DMA_INT_ERR_CLR 0x10 +#define DMA_TC 0x14 +#define DMA_ERR 0x18 +#define DMA_CH_EN 0x1C +#define DMA_CH_BUSY 0x20 +#define DMA_CSR 0x24 +#define DMA_SYNC 0x28 + +#define DMA_C0_DevRegBase 0x40 +#define DMA_C0_DevDtBase 0x80 + +#define DMA_CH_CFG_REG_OFFSET 0x20 +#define DMA_C0_CSR 0x100 +#define DMA_C0_CFG 0x104 +#define DMA_C0_SrcAddr 0x108 +#define DMA_C0_DstAddr 0x10C +#define DMA_C0_LLP 0x110 +#define DMA_C0_SIZE 0x114 + +/* bit mapping of main configuration status register(CSR) */ +#define DMA_CSR_M1ENDIAN 0x00000004 +#define DMA_CSR_M0ENDIAN 0x00000002 +#define DMA_CSR_DMACEN 0x00000001 + +/* bit mapping of channel control register */ +#define DMA_CSR_TC_MSK 0x80000000 +#define DMA_CSR_CHPRJ_HIGHEST 0x00C00000 +#define DMA_CSR_CHPRJ_2ND 0x00800000 +#define DMA_CSR_CHPRJ_3RD 0x00400000 +#define DMA_CSR_PRTO3 0x00200000 +#define DMA_CSR_PRTO2 0x00100000 +#define DMA_CSR_PRTO1 0x00080000 +#define DMA_CSR_SRC_BURST_SIZE_1 0x00000000 +#define DMA_CSR_SRC_BURST_SIZE_4 0x00010000 +#define DMA_CSR_SRC_BURST_SIZE_8 0x00020000 +#define DMA_CSR_SRC_BURST_SIZE_16 0x00030000 +#define DMA_CSR_SRC_BURST_SIZE_32 0x00040000 +#define DMA_CSR_SRC_BURST_SIZE_64 0x00050000 +#define DMA_CSR_SRC_BURST_SIZE_128 0x00060000 +#define DMA_CSR_SRC_BURST_SIZE_256 0x00070000 + +#define DMA_CSR_ABT 0x00008000 +#define DMA_CSR_SRC_WIDTH_8 0x00000000 +#define DMA_CSR_SRC_WIDTH_16 0x00000800 +#define DMA_CSR_SRC_WIDTH_32 0x00001000 + +#define DMA_CSR_DST_WIDTH_8 0x00000000 +#define DMA_CSR_DST_WIDTH_16 0x00000100 +#define DMA_CSR_DST_WIDTH_32 0x00000200 + +#define DMA_CSR_MODE_NORMAL 0x00000000 +#define DMA_CSR_MODE_HANDSHAKE 0x00000080 + +#define DMA_CSR_SRC_INCREMENT 0x00000000 +#define DMA_CSR_SRC_DECREMENT 0x00000020 +#define DMA_CSR_SRC_FIX 0x00000040 + +#define DMA_CSR_DST_INCREMENT 0x00000000 +#define DMA_CSR_DST_DECREMENT 0x00000008 +#define DMA_CSR_DST_FIX 0x00000010 + +#define DMA_CSR_SRC_SEL 0x00000004 +#define DMA_CSR_DST_SEL 0x00000002 +#define DMA_CSR_CH_ENABLE 0x00000001 + + +#define DMA_MAX_SIZE 0x10000 +#define DAM_CHANNEL_NUMBER 8 + + +typedef struct +{ + UINT32 enable:1; + UINT32 dst_sel:1; + UINT32 src_sel:1; + UINT32 dst_ctrl:2; + UINT32 src_ctrl:2; + UINT32 mode:1; + UINT32 dst_width:3; + UINT32 src_width:3; + UINT32 reserved1:1; + UINT32 abt:1; + UINT32 src_size:3; + UINT32 prot:3; + UINT32 priority:2; + UINT32 reserved0:7; + UINT32 tc_msk:1; +}fLib_DMA_CH_CSR_t; + +typedef struct +{ + UINT32 int_tc_msk:1; + UINT32 int_err_msk:1; + UINT32 reserved0:30; +}fLib_DMA_CH_CFG_t; + +typedef struct +{ + UINT32 master_id:1; + UINT32 reserved:1; + UINT32 link_list_addr:30; +}fLib_DMA_CH_LLP_t; + +typedef struct +{ + UINT32 size:12; + UINT32 reserved:4; + + UINT32 dst_sel:1; + UINT32 src_sel:1; + UINT32 dst_ctrl:2; + UINT32 src_ctrl:2; + UINT32 dst_width:3; + UINT32 src_width:3; + UINT32 tc_msk:1; + UINT32 reserved1:3; +}fLib_DMA_LLP_CTRL_t; + +typedef struct +{ + fLib_DMA_CH_CSR_t csr; + fLib_DMA_CH_CFG_t cfg; + UINT32 src_addr; + UINT32 dst_addr; + fLib_DMA_CH_LLP_t llp; + UINT32 size; + UINT32 dummy[2]; +}fLib_DMA_CH_t; + +typedef struct +{ + UINT32 src_addr; + UINT32 dst_addr; + fLib_DMA_CH_LLP_t llp; + fLib_DMA_LLP_CTRL_t llp_ctrl; +}fLib_DMA_LLD_t; + + +typedef struct +{ + UINT32 dma_int; + UINT32 dma_int_tc; + UINT32 dma_int_tc_clr; + UINT32 dma_int_err; + UINT32 dma_int_err_clr; + UINT32 dma_tc; + UINT32 dma_err; + UINT32 dma_ch_enable; + UINT32 dma_ch_busy; + UINT32 dma_csr; + UINT32 dma_sync; + UINT32 dummy0[5]; + + UINT32 dma_ch_dev_reg_base[8]; + UINT32 dummy1[8]; + + UINT32 dma_ch_dev_dt_base[8]; + + UINT32 dummy2[24]; + + fLib_DMA_CH_t dma_ch[7]; +}fLib_DMA_Reg_t; + + +#ifdef not_complete_yet +/* ------------------------------------------------------------------------------- + * API + * ------------------------------------------------------------------------------- + */ + +extern int fLib_IsDMAChannelBusy(INT32 Channel); +extern int fLib_IsDMAChannelEnable(INT32 Channel); +extern UINT32 fLib_GetDMAIntStatus(void); +extern UINT32 fLib_GetDMAChannelIntStatus(INT32 Channel); +extern int fLib_GetDMABusyStatus(void); +extern int fLib_GetDMAEnableStatus(void); + +extern void fLib_InitDMA(UINT32 M0_BigEndian, UINT32 M1_BigEndian, UINT32 Sync); +extern void fLib_EnableDMAChannel(INT32 Channel); +extern void fLib_ClearDMAChannelIntStatus(INT32 Channel); + +extern void fLib_SetDMAChannelCfg(INT32 Channel, fLib_DMA_CH_CSR_t Csr); +extern fLib_DMA_CH_CSR_t fLib_GetDMAChannelCfg(INT32 Channel); +extern void fLib_DMA_CHIntMask(INT32 Channel, fLib_DMA_CH_CFG_t Mask); +extern void fLib_DMA_CHLinkList(INT32 Channel, fLib_DMA_CH_LLP_t LLP); +extern void fLib_DMA_CHDataCtrl(INT32 Channel, UINT32 SrcAddr, UINT32 DstAddr, UINT32 Size); +#endif /* end_of_not */ + +#endif \ No newline at end of file diff --git a/arch/arm/mach-moxart/entry-macro.S b/arch/arm/mach-moxart/entry-macro.S new file mode 100644 index 00000000..a0dc5039 --- /dev/null +++ b/arch/arm/mach-moxart/entry-macro.S @@ -0,0 +1,42 @@ +/* + * + * jimmy_chen@moxa.com.tw + */ + +//#include +#include +#if defined(CONFIG_ARCH_MOXART) + .macro disable_fiq + .endm + + .macro get_fiqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(IO_ADDRESS(CPE_IC_BASE)+FIQ_STATUS_REG) + ldr \irqstat, [\base] + mov \irqnr, #32 +2001: + tst \irqstat, #1 + bne 2002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #64 + bcc 2001b +2002: + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(CPE_IC_BASE+IRQ_STATUS_REG) + ldr \irqstat, [\base] + mov \irqnr, #0 +2003: + tst \irqstat, #1 + bne 2004f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #32 + bcc 2003b +2004: + .endm + + .macro irq_prio_table + .endm +#endif diff --git a/arch/arm/mach-moxart/ftpci.c b/arch/arm/mach-moxart/ftpci.c new file mode 100644 index 00000000..e4f08aed --- /dev/null +++ b/arch/arm/mach-moxart/ftpci.c @@ -0,0 +1,278 @@ +/* + ftpci.h + maintened by ivan wang 2004/8/18 11:25 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_CPE120_PLATFORM +#include +#endif + +#define DEBUG_FTPCI 1 + +#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3) ) +static spinlock_t ftpci_lock; +struct pci_dev *pci_bridge=NULL; +static unsigned int pci_config_addr; +static unsigned int pci_config_data; +int ftpci_probed=0; + +static int ftpci_read_config_byte(struct pci_dev *dev, int where, u8 *val) +{ + unsigned long flags; + u32 v; + unsigned int shift; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(dev->bus->number,dev->devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + shift = (where&0x3)*8; + *val = (v>>shift)&0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_read_config_word(struct pci_dev *dev, int where, u16 *val) +{ + unsigned long flags; + u32 v; + unsigned int shift; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(dev->bus->number,dev->devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + shift = (where&0x3)*8; + *val = (v>>shift)&0xffff; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_read_config_dword(struct pci_dev *dev, int where, u32 *val) +{ + unsigned long flags; + u32 v; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(dev->bus->number,dev->devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + u32 org_val; + unsigned long flags; + unsigned int shift; + + shift = (where&0x3)*8; + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(dev->bus->number,dev->devfn,where); + org_val=*(volatile unsigned int *)pci_config_data; + org_val=(org_val&~(0xff<bus->number, dev->devfn, where); + org_val=*(volatile unsigned int *)pci_config_data; + org_val=(org_val&~(0xffff<bus->number, dev->devfn, where); + *(volatile unsigned int *)pci_config_data=val; + spin_unlock_irqrestore(&ftpci_lock, flags); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ftpci_ops = { + .read = ftpci_read_config_byte, + //.read_word = ftpci_read_config_word, +// .read_dword = ftpci_read_config_dword, + .write = ftpci_write_config_byte, +// .write_word = ftpci_write_config_word, +// .write_dword= ftpci_write_config_dword, +}; + +/* using virtual address for pci_resource_start() function*/ +static struct resource pci_io = { + .name = "PCI io", + .start = (CPE_PCI_BASE+SZ_4K), + .end = (CPE_PCI_BASE+SZ_1M), + .flags = IORESOURCE_IO, +}; +/* using physical address for memory resource*/ +static struct resource pci_mem = { + .name = "PCI non-prefetchable", + .start = PCI_MEM_BASE, + .end = PCI_MEM_END, + .flags = IORESOURCE_MEM, +}; + +//int __init ftpci_setup_resource(struct resource **resource) +void __init ftpci_setup_resource(struct resource **resource) +{ + if (request_resource(&ioport_resource, &pci_io)) { + printk(KERN_ERR "PCI: unable to allocate io region\n"); +// return -EBUSY; + } + if (request_resource(&iomem_resource, &pci_mem)) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region\n"); +// return -EBUSY; + } + + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + + resource[0] = &pci_io; + resource[1] = &pci_mem; + +// return 1; +} + +inline int ftpci_get_irq(void) +{ + unsigned int status; + ftpci_read_config_dword(pci_bridge, 0x4c, &status); +//printk("ftpci_get_irq,status=0x%x\n",status); + status=(status>>28); + if(status&0x1) + return 0; + if(status&0x2) + return 1; + if(status&0x4) + return 2; + if(status&0x8) + return 3; + return -1; +} + +void ftpci_clear_irq(unsigned int irq) +{ + //int i; + unsigned int status; + ftpci_read_config_dword(pci_bridge, 0x4c, &status); + if(irq==0) + status=(status&0xfffffff)|((0x1)<<28); + else if(irq==1) + status=(status&0xfffffff)|((0x2)<<28); + else if(irq==2) + status=(status&0xfffffff)|((0x4)<<28); + else if(irq==3) + status=(status&0xfffffff)|((0x8)<<28); + ftpci_write_config_dword(pci_bridge, 0x4c, status); +} + +static int ftpci_probe(unsigned int addr_p) +{ + unsigned int *addr=(unsigned int*)addr_p; + *(volatile unsigned int *)addr=0x80000000; + if(*(volatile unsigned int *)addr==0x80000000) + ftpci_probed=1; + else + ftpci_probed=0; + *(volatile unsigned int *)addr=0x0; + return ftpci_probed; +} + + +void __init ftpci_init(void *sysdata) +{ + u16 val; + + pci_config_addr=CPE_PCI_BASE+FTPCI_CFG_ADR_REG; + pci_config_data=CPE_PCI_BASE+FTPCI_CFG_DATA_REG; + + if(!ftpci_probe(pci_config_addr)) + return; + + pci_scan_bus(0, &ftpci_ops, sysdata); + pci_bridge=pci_find_device(PCI_BRIDGE_VENID,PCI_BRIDGE_DEVID,NULL); + if (pci_bridge == NULL) + return; + + spin_lock_init(&ftpci_lock); + + // Enable the Interrupt Mask (INTA/INTB/INTC/INTD) + ftpci_read_config_word(pci_bridge,PCI_INT_MASK,&val); + val|=(PCI_INTA_ENABLE|PCI_INTB_ENABLE|PCI_INTC_ENABLE|PCI_INTD_ENABLE); + ftpci_write_config_word(pci_bridge,PCI_INT_MASK,val); + + // Write DMA Start Address/Size Data to the Bridge configuration space + ftpci_write_config_dword(pci_bridge, PCI_MEM_BASE_SIZE1, FTPCI_BASE_ADR_SIZE_1GB); +} + +/* + * This routine handles multiple bridges. + */ +static u8 __init cpe_swizzle(struct pci_dev *dev, u8 *pinp) +{ + return 0; +} + +static int __init cpe_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + //printk("cpe_map_irq,slot=%d pin=%d\n",PCI_SLOT(dev->devfn),pin); + switch(PCI_SLOT(dev->devfn)) + { + case 8: + return VIRQ_PCI_A; + case 9: + return VIRQ_PCI_B; + case 10: + return VIRQ_PCI_C; + case 11: + return VIRQ_PCI_D; + default: + //printk("Not Support Slot %d\n",slot); + break; + } + return -1; +} + +struct hw_pci cpe_pci __initdata = { +// .setup_resources = ftpci_setup_resource, +// .init = ftpci_init, + .swizzle = cpe_swizzle, + .map_irq = cpe_map_irq, +}; diff --git a/arch/arm/mach-moxart/gpio.c b/arch/arm/mach-moxart/gpio.c new file mode 100644 index 00000000..91af2a76 --- /dev/null +++ b/arch/arm/mach-moxart/gpio.c @@ -0,0 +1,181 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define VICTOR_USE_LOCK_IRQ +static mcpu_gpio_reg_t *gpio_reg=(mcpu_gpio_reg_t *)CPE_GPIO_VA_BASE; +static spinlock_t gpio_lock=SPIN_LOCK_UNLOCKED; + +/* + * To set the GPIO mode for INPUT or OUTPUT + */ +void mcpu_gpio_inout(u32 gpio, int inout) +{ +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif + switch ( inout ) { + case MCPU_GPIO_INPUT : + writel(readl(&gpio_reg->pin_dir)&~gpio, &gpio_reg->pin_dir); + break; + case MCPU_GPIO_OUTPUT : + writel(readl(&gpio_reg->pin_dir)|gpio, &gpio_reg->pin_dir); + break; + } +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif +} +EXPORT_SYMBOL(mcpu_gpio_inout); + +/* + * To get the GPIO which mode, INPUT or OUTPUT + */ +u32 mcpu_gpio_get_inout(u32 gpio) +{ + u32 ret; +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif + if ( readl(&gpio_reg->pin_dir) & gpio ) + ret = MCPU_GPIO_OUTPUT; + else + ret = MCPU_GPIO_INPUT; +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif + return ret; +} +EXPORT_SYMBOL(mcpu_gpio_get_inout); + +/* + * To set the GPIO ouput signal to high or low + */ +void mcpu_gpio_set(u32 gpio, int highlow) +{ +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif + switch ( highlow ) { + case MCPU_GPIO_HIGH : + writel(readl(&gpio_reg->data_out)|gpio, &gpio_reg->data_out); + break; + case MCPU_GPIO_LOW : + writel(readl(&gpio_reg->data_out)&~gpio, &gpio_reg->data_out); + break; + } +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif +} +EXPORT_SYMBOL(mcpu_gpio_set); + +/* + * to get the GPIO input which level, high or low + */ +u32 mcpu_gpio_get(u32 gpio) +{ + u32 ret; +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif +#if 0 // mask by Victor Yu. 04-20-2007 + ret = readl(&gpio_reg->data_in) & gpio; +#else + ret = readl(&gpio_reg->pin_dir); + if ( ret & gpio ) // this is output GPIO + ret = readl(&gpio_reg->data_out) & gpio; + else + ret = readl(&gpio_reg->data_in) & gpio; +#endif +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif + return ret; +} +EXPORT_SYMBOL(mcpu_gpio_get); + +/* + * To set thie GPIO to work GPIO mode + */ +void mcpu_gpio_mp_set(u32 gpio) +{ +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif + *(volatile unsigned int *)(CPE_PMU_VA_BASE+0x100) |= gpio; +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif +} +EXPORT_SYMBOL(mcpu_gpio_mp_set); + +/* + * To set the GPIO for component mode + */ +void mcpu_gpio_mp_clear(u32 gpio) +{ +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + unsigned long flags; +#endif + +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_lock_irqsave(&gpio_lock, flags); +#else + spin_lock(&gpio_lock); +#endif + *(volatile unsigned int *)(CPE_PMU_VA_BASE+0x100) &= ~gpio; +#ifdef VICTOR_USE_LOCK_IRQ // add by Victor Yu. 07-25-2007 + spin_unlock_irqrestore(&gpio_lock, flags); +#else + spin_unlock(&gpio_lock); +#endif +} +EXPORT_SYMBOL(mcpu_gpio_mp_clear); diff --git a/arch/arm/mach-moxart/head.S b/arch/arm/mach-moxart/head.S new file mode 100644 index 00000000..d83226a7 --- /dev/null +++ b/arch/arm/mach-moxart/head.S @@ -0,0 +1,91 @@ +/* + * uClinux kernel startup code for s5c7375 + * which has no proper bootloader for linux startup + * because of XIP. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Kernel startup entry point. + */ + +ENTRY(led1) +@ bl led +@led1: + ldr r2, =0x98700000 + mov r3, #0x0000000f + strb r3,[r2] + mov pc,lr +ENTRY(led2) +@led2: + ldr r2, =0x98700000 + mov r3, #0x0000000e + strb r3,[r2] + mov pc,lr +ENTRY(led3) +@led3: + ldr r2, =0x98700000 + mov r3, #0x0000000d + strb r3,[r2] + mov pc,lr +ENTRY(led4) +@led4: + ldr r2, =0x902ffffc + mov r3, #4 + strb r3,[r2] + mov pc,lr +ENTRY(led5) +@led5: + ldr r2, =0x902ffffc + mov r3, #5 + strb r3,[r2] + mov pc,lr +ENTRY(led6) +@led6: + ldr r2, =0x902ffffc + mov r3, #6 + strb r3,[r2] + mov pc,lr + +ENTRY(led7) +@led7: + ldr r2, =0x902ffffc + mov r3, #7 + strb r3,[r2] + mov pc,lr + +ENTRY(led8) +@led8: + ldr r2, =0x902ffffc + mov r3, #8 + strb r3,[r2] + mov pc,lr + +ENTRY(led9) +@led9: + ldr r2, =0x902ffffc + mov r3, #9 + strb r3,[r2] + mov pc,lr + +ENTRY(msg) +@msg: + ldr r2, =0xB0900000 + mov r3, #0x70 + strb r3,[r2] + mov pc,lr +ENTRY(hank) +@msg: + ldr r2, =0x98700000 + mov r3, #0x05 + strb r3,[r2] + mov pc,lr +#include "../kernel/head.S" diff --git a/arch/arm/mach-moxart/irq.c b/arch/arm/mach-moxart/irq.c new file mode 100644 index 00000000..f4fcd105 --- /dev/null +++ b/arch/arm/mach-moxart/irq.c @@ -0,0 +1,335 @@ + +//#include +#include +#include +#include + +//#include +#include +#include +#include +#include +#ifdef CONFIG_PCI +#include +#endif // CONFIG_PCI + +//#define VICTOR_USE_IRQ_LOCK // add by Victor Yu. 07-31-2007 + +#if 0 // mask by Victtor Yu. 03-15-2007 +static spinlock_t cpe_int_lock; +#else +static spinlock_t cpe_int_lock=SPIN_LOCK_UNLOCKED; +#endif + +#if 0 // add by Victor Yu. 05-17-2005 +#include +#if 0 // mask by Victor Yu, 03-15-2007 +struct irqchip cpe_irq_chip = { + .ack = cpe_mask_ack_irq, + .mask = cpe_mask_irq, + .unmask = cpe_unmask_irq, +}; +#endif +#endif + +inline void cpe_irq_set_mode(unsigned int base_p,unsigned int irq,unsigned int edge) +{ + if ( edge ) + *(volatile unsigned int *)(base_p+IRQ_MODE_REG)|=(1< +#include +#include +#include + +//#include +#include +#include +#include +#include +#ifdef CONFIG_PCI +#include +#endif // CONFIG_PCI + +#if 0 // mask by Victtor Yu. 03-15-2007 +static spinlock_t cpe_int_lock; +#else +static spinlock_t cpe_int_lock=SPIN_LOCK_UNLOCKED; +#endif + +#if 0 // add by Victor Yu. 05-17-2005 +#include +#if 0 // mask by Victor Yu, 03-15-2007 +struct irqchip cpe_irq_chip = { + .ack = cpe_mask_ack_irq, + .mask = cpe_mask_irq, + .unmask = cpe_unmask_irq, +}; +#endif +#endif + +inline void cpe_irq_set_mode(unsigned int base_p,unsigned int irq,unsigned int edge) +{ + if ( edge ) + *(volatile unsigned int *)(base_p+IRQ_MODE_REG)|=(1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Luke Lee 03/23/2005 ins 1 + +#ifdef CONFIG_PCI +#ifdef CONFIG_CPE120_PLATFORM +#include +#endif + +#define DEBUG_FTPCI 1 + +#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3) ) +static spinlock_t ftpci_lock; +struct pci_dev *pci_bridge=NULL; +static unsigned int pci_config_addr; +static unsigned int pci_config_data; +int ftpci_probed=0; + +// Luke Lee 03/21/2005 mod begin +static int ftpci_write_config_dlocal(struct pci_bus *bus, unsigned int devfn, int where, u32 val) +{ + unsigned long flags; + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(0, 0, where); + *(volatile unsigned int *)pci_config_data=val; + spin_unlock_irqrestore(&ftpci_lock, flags); + return PCIBIOS_SUCCESSFUL; +} +static int ftpci_write_config_wlocal(struct pci_bus *bus, unsigned int devfn, int where, u16 val) +{ + u32 org_val; + unsigned long flags; + unsigned int shift; + + shift = (where&0x3)*8; + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(0,0 , where); + org_val=*(volatile unsigned int *)pci_config_data; + org_val=(org_val&~(0xffff<>shift)&0xffff; + return PCIBIOS_SUCCESSFUL; +} +static int ftpci_read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 *val) +{ + unsigned long flags; + u32 v; + unsigned int shift; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(bus->number,devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + shift = (where&0x3)*8; + *val = (v>>shift)&0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 *val) +{ + unsigned long flags; + u32 v; + unsigned int shift; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(bus->number,devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + shift = (where&0x3)*8; + *val = (v>>shift)&0xffff; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val) +{ + unsigned long flags; + u32 v; + + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(bus->number,devfn,where); + v=*(volatile unsigned int *)pci_config_data; + spin_unlock_irqrestore(&ftpci_lock, flags); + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int ftpci_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) +{ + u32 org_val; + unsigned long flags; + unsigned int shift; + + shift = (where&0x3)*8; + spin_lock_irqsave(&ftpci_lock, flags); + *(volatile unsigned int *)pci_config_addr=CONFIG_CMD(bus->number,devfn,where); + org_val=*(volatile unsigned int *)pci_config_data; + org_val=(org_val&~(0xff<number, devfn, where); + org_val=*(volatile unsigned int *)pci_config_data; + org_val=(org_val&~(0xffff<number, devfn, where); + *(volatile unsigned int *)pci_config_data=val; + spin_unlock_irqrestore(&ftpci_lock, flags); + return PCIBIOS_SUCCESSFUL; +} +// Luke Lee 03/21/2005 mod end + +// Luke Lee 03/21/2005 ins begin +static int ftpci_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + int r; + switch (size) { + case 1: + r = ftpci_read_config_byte(bus,devfn,where,(u8*)val); // Luke Lee TOFIX 03/22/2005 : convert to (u8*) -- beware of endian ! + break; + + case 2: + r = ftpci_read_config_word(bus,devfn,where,(u16*)val); // Luke Lee TOFIX 03/22/2005 : convert to (u16*) -- beware of endian ! + break; + + default: + r = ftpci_read_config_dword(bus,devfn,where,val); + break; + } + + return r; +} + +static int ftpci_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + int r; + switch (size) { + case 1: + r = ftpci_write_config_byte(bus, devfn, where, val); + break; + + case 2: + r = ftpci_write_config_word(bus, devfn, where, val); + break; + + case 4: + r = ftpci_write_config_dword(bus, devfn, where, val); + break; + default: + printk( "Invalid size for ftpci_write()\n" ); + r = PCIBIOS_FUNC_NOT_SUPPORTED; // Luke Lee 03/23/2005 ins 1 + } + + return r; +} + +// Luke Lee 03/21/2005 ins end + +static struct pci_ops ftpci_ops = { + // Luke Lee 03/21/2005 mod begin + .read = ftpci_read_config, + .write = ftpci_write_config, + // Luke Lee 03/21/2005 mod end +}; + +/* using virtual address for pci_resource_start() function*/ +static struct resource pci_io = { + .name = "PCI io", + .start = PCI_IO_VA_BASE, + .end = PCI_IO_VA_END, + .flags = IORESOURCE_IO, +}; +/* using physical address for memory resource*/ +static struct resource pci_mem = { + .name = "PCI non-prefetchable", + .start = PCI_MEM_BASE, + .end = PCI_MEM_END, + .flags = IORESOURCE_MEM, +}; + +// Luke Lee 03/23/2005 unrem 1 rem 1 +int __init ftpci_setup_resource(struct resource **resource) +//void __init ftpci_setup_resource(struct resource **resource) +{ + if (request_resource(&ioport_resource, &pci_io)) { + printk(KERN_ERR "PCI: unable to allocate io region\n"); + return -EBUSY; // Luke Lee 03/23/2005 unrem 1 + } + if (request_resource(&iomem_resource, &pci_mem)) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region\n"); + return -EBUSY; // Luke Lee 03/23/2005 unrem 1 + } + + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + + resource[0] = &pci_io; + resource[1] = &pci_mem; + + return 1; // Luke Lee 03/23/2005 unrem 1 +} + +inline int ftpci_get_irq(void) +{ + unsigned int status; + ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, &status); // Luke Lee 03/22/2005 mod 1 +printk("ftpci_get_irq,status=0x%x\n",status); + status=(status>>28); + if(status&0x1) + return 0; + if(status&0x2) + return 1; + if(status&0x4) + return 2; + if(status&0x8) + return 3; + return -1; +} + +void ftpci_clear_irq(unsigned int irq) +{ + //int i; + unsigned int status; + ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, &status); // Luke Lee 03/22/2005 mod 1 + if(irq==0) + status=(status&0xfffffff)|((0x1)<<28); + else if(irq==1) + status=(status&0xfffffff)|((0x2)<<28); + else if(irq==2) + status=(status&0xfffffff)|((0x4)<<28); + else if(irq==3) + status=(status&0xfffffff)|((0x8)<<28); + ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, status); // Luke Lee 03/22/2005 mod 1 +} + +static int ftpci_probe(unsigned int addr_p) +{ + unsigned int *addr=(unsigned int*)addr_p; + *(volatile unsigned int *)addr=0x80000000; + if(*(volatile unsigned int *)addr==0x80000000) + ftpci_probed=1; + else + ftpci_probed=0; + *(volatile unsigned int *)addr=0x0; + return ftpci_probed; +} + + +void __init ftpci_preinit(void /**sysdata*/) // Luke Lee 03/22/2005 mod 1 +{ + u16 val; + printk( "ftpci_init()\n\r" ); // Luke Lee 03/22/2005 ins 1 + pci_config_addr=CPE_PCI_VA_BASE+FTPCI_CFG_ADR_REG; + pci_config_data=CPE_PCI_VA_BASE+FTPCI_CFG_DATA_REG; +#if 0 + if(!ftpci_probe(pci_config_addr)) + return; + + //pci_scan_bus(0, &ftpci_ops, sysdata); // Luke Lee 03/22/2005 rem 1 + pci_bridge=pci_find_device(PCI_BRIDGE_VENID,PCI_BRIDGE_DEVID,NULL); + if (pci_bridge == NULL) + return; +#endif + spin_lock_init(&ftpci_lock); + + // Enable the Interrupt Mask (INTA/INTB/INTC/INTD) + ftpci_read_config_wlocal(pci_bridge->bus,pci_bridge->devfn,PCI_INT_MASK,&val); // Luke Lee 03/22/2005 mod 1 + val|=(PCI_INTA_ENABLE|PCI_INTB_ENABLE|PCI_INTC_ENABLE|PCI_INTD_ENABLE); + ftpci_write_config_wlocal(pci_bridge->bus,pci_bridge->devfn,PCI_INT_MASK,val);// Luke Lee 03/22/2005 mod 1 + + // Write DMA Start Address/Size Data to the Bridge configuration space + ftpci_write_config_dlocal(pci_bridge->bus, pci_bridge->devfn, PCI_MEM_BASE_SIZE1, FTPCI_BASE_ADR_SIZE_1GB); // Luke Lee 03/22/2005 mod 1 +} + +/* + * This routine handles multiple bridges. + */ +static u8 __init cpe_swizzle(struct pci_dev *dev, u8 *pinp) +{ + printk( "cpe_swizzle(%X,%X)\n\r",(unsigned)dev,(unsigned)pinp ); // Luke Lee 03/22/2005 ins 1 + return 0; +} + +static int __init cpe_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + printk("cpe_map_irq,slot=%d pin=%d\n",PCI_SLOT(dev->devfn),pin); + switch(PCI_SLOT(dev->devfn)) + { + case 8: + return VIRQ_PCI_A; + case 9: + return VIRQ_PCI_B; + case 10: + return VIRQ_PCI_C; + case 11: + return VIRQ_PCI_D; + default: + //printk("Not Support Slot %d\n",slot); + break; + } + return -1; +} + +#if 0 // Luke Lee 03/22/2005 rem block +struct hw_pci cpe_pci __initdata = { + .setup_resources = ftpci_setup_resource, + .init = ftpci_init, + .swizzle = cpe_swizzle, + .map_irq = cpe_map_irq, +}; +#endif + +// Luke Lee 03/22/2005 ins begin + +int __init ftpci_setup(int nr, struct pci_sys_data *sys) +{ + int ret = 0; + + if (nr == 0) { + sys->mem_offset = CPE_PCI_MEM; // Luke Lee TOFIX : 03/22/2005 : or CPE_PCI_BASE ??? + ret = ftpci_setup_resource(sys->resource); + } + return ret; +} + +static struct pci_bus *ftpci_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &ftpci_ops, sys); +} + +static struct hw_pci cpe_pci __initdata = { + .swizzle = cpe_swizzle, + .map_irq = cpe_map_irq, + .setup = ftpci_setup, + .nr_controllers = 1, + .scan = ftpci_scan_bus, + // TOFIX + .preinit = ftpci_preinit, + //.postinit = pci_v3_postinit, // no post init function +}; + +static int __init a320_pci_init(void) +{ + pci_common_init(&cpe_pci); + return 0; +} + +subsys_initcall(a320_pci_init); + +// Luke Lee 03/22/2005 ins begin +#endif //CONFIG_PCI diff --git a/arch/arm/mach-moxart/timer.c b/arch/arm/mach-moxart/timer.c new file mode 100644 index 00000000..53a0543e --- /dev/null +++ b/arch/arm/mach-moxart/timer.c @@ -0,0 +1,193 @@ +/* + * time.c Timer functions for cpe + */ +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_TIMER 2 +#define USED_TIMER 1 +#define SET_COUNTER (APB_CLK / HZ) + +cpe_time_reg_t *TimerBase[] = +{ + 0, + (cpe_time_reg_t *)CPE_TIMER1_VA_BASE, + (cpe_time_reg_t *)CPE_TIMER2_VA_BASE +}; + +static int cpe_timer_enable(int timer) +{ + cpe_time_ctrl_t *t=(cpe_time_ctrl_t *)(CPE_TIMER1_VA_BASE+TIMER_CR); + + if ((timer == 0) || (timer > MAX_TIMER)) + return 0; + + switch(timer) + { + case 1: + t->Tm1En=1; + t->Tm1OfEn=1; +#if 1 // add by Victor Yu. 06-01-2005 + t->Tm1Clock = 0; // use PCLK +#endif + break; + case 2: + t->Tm2En=1; + t->Tm2OfEn=1; +#if 1 // add by Victor Yu. 06-01-2005 + t->Tm2Clock = 0; // use PCLK +#endif + break; + case 3: + t->Tm3En=1; + t->Tm3OfEn=1; +#if 1 // add by Victor Yu. 06-01-2005 + t->Tm3Clock = 0; // use PCLK +#endif + break; + + default: + break; + } + + return 1; +} + +#if 0 // mask by Victor Yu. 01-31-2008 +/* This routine stops the specified timer hardware. */ +unsigned int cpe_timer_disable(unsigned int timer) +{ + cpe_time_ctrl_t *t=(cpe_time_ctrl_t *)(CPE_TIMER1_VA_BASE + TIMER_CR); + + if ((timer == 0) || (timer > MAX_TIMER)) + return 0; + + switch(timer) + { + case 1: + t->Tm1En=0; + t->Tm1OfEn=0; + break; + case 2: + t->Tm2En=0; + t->Tm2OfEn=0; + break; + case 3: + t->Tm3En=0; + t->Tm3OfEn=0; + break; + + default: + break; + + } + + return 1; +} +#endif + +static void cpe_timer_set_counter(int timer, unsigned int value) +{ + volatile cpe_time_reg_t *t = TimerBase[timer]; + t->TimerValue = value; +} + +static void cpe_timer_set_reload(int timer, unsigned int value) +{ + volatile cpe_time_reg_t *t = TimerBase[timer]; + t->TimerLoad = value; +#if 1 // add by Victor Yu. 01-31-2008 + t->TimerMatch1 = 0xffffffff; + t->TimerMatch2 = 0xffffffff; +#endif +} + +// -------------------------------------------------------------------- +// warning: +// timer = 1, 2, 3 +// -------------------------------------------------------------------- +static unsigned long cpe_timer_get_counter(int timer) +{ + volatile cpe_time_reg_t *t = TimerBase[timer]; + return (volatile unsigned long)(t->TimerValue); +} + +unsigned long cpe_gettimeoffset (void) +{ +#if 1 // add by Victor Yu. 02-26-2007 + unsigned long offsetticks; + + offsetticks = cpe_timer_get_counter(USED_TIMER); + offsetticks = SET_COUNTER - offsetticks; +#if 0 // mask by Victor Yu. 01-31-2008 + if ( (*(volatile unsigned int *)(CPE_IC_VA_BASE+IRQ_STATUS_REG) & IRQ_TIMER1) || + (*(volatile unsigned int *)(CPE_IC_VA_BASE+IRQ_STATUS_REG) & IRQ_TIMER1) ) { +#else + if ( *(volatile unsigned int *)(CPE_TIMER1_VA_BASE+TIMER_INTR_STATE) ) { + //printk("[has timer interrupt pending , %d !]\n", offsetticks); +#endif + offsetticks = cpe_timer_get_counter(USED_TIMER); + offsetticks = SET_COUNTER - offsetticks; + offsetticks += SET_COUNTER; + } + offsetticks = offsetticks / (APB_CLK / 1000000); // tansfer ticks to usec + return offsetticks; +#else // 02-26-2007 + return 0; +#endif // 02-26-2007 +} + +#if 1 // add by Victor Yu. 05-25-2005 +static irqreturn_t cpe_timer_interrupt(int irq, void *dev_id) +{ + //do_timer(regs); // mask by Victor Yu. 06-01-2005 + timer_tick(); // add by Victor Yu. 06-01-2005 +#if 1 // add by Victor Yu. 01-31-2008 + *(volatile unsigned int *)(CPE_TIMER1_VA_BASE+TIMER_INTR_STATE) = 0; +#endif + return IRQ_HANDLED; +} + +static struct irqaction cpe_timer_irq = { + .name = "Moxa CPE timer interrupt", + .flags = SA_INTERRUPT, + .handler = cpe_timer_interrupt +}; + +void __init moxa_time_init(void) +{ +//#ifdef TIMER_INC_MODE +#if 0 // mask by Victor Yu. 01-31-2008 + cpe_timer_set_reload(USED_TIMER, 0xffffffff - SET_COUNTER); + cpe_timer_set_counter(USED_TIMER, 0xffffffff - SET_COUNTER); +#else + cpe_timer_set_reload(USED_TIMER, SET_COUNTER); + cpe_timer_set_counter(USED_TIMER, SET_COUNTER); +#endif + + if( !cpe_timer_enable(USED_TIMER) ) { + panic("can not enable timer\n"); + } + + printk("IRQ timer at interrupt number 0x%x clock %d\r\n",IRQ_TIMER1,APB_CLK); + //moxa_int_set_irq(IRQ_TIMER1, EDGE, L_ACTIVE); + cpe_int_set_irq(IRQ_TIMER1, EDGE, L_ACTIVE); + setup_irq(IRQ_TIMER1, &cpe_timer_irq); +} +#endif + +struct sys_timer moxa_timer = { + .init = moxa_time_init, + .offset = cpe_gettimeoffset, +}; diff --git a/arch/arm/mach-p2001/Kconfig b/arch/arm/mach-p2001/Kconfig new file mode 100644 index 00000000..fd0888c1 --- /dev/null +++ b/arch/arm/mach-p2001/Kconfig @@ -0,0 +1,61 @@ +if ARCH_P2001 + +menu "P2001 Options" + depends on ARCH_P2001 + +config SYSCLK + int 'SysClk' + default 73728000 + help + The default sysclk is 73.728 MHz. For the ethernet unit to + work more than 25 MHz are needed. Overclocking starts at + 75 MHz. The following system clock frequencies are allowed: + 12288000: 12.288 MHz + 24576000: 24.576 MHz + 36864000: 36.864 MHz + 49152000: 49.152 MHz + 61440000: 61.440 MHz + 73728000: 73.728 MHz + 86016000: 86.016 MHz + 98304000: 98.304 MHz + 110592000: 110.592 MHz + +config P2001_AUTO_DETECT_SDRAM + bool 'Automatic SDRAM detection' + default y + help + The automatic SDRAM detection is done by writing at each + memory bank. The memory is over, when a read/write error + occured or a wrap to the first memory bank is detected. + + The search area is specified by CONFIG_DRAM_BASE and + CONFIG_DRAM_SIZE ! + + The P2001 can have up to 64 MB SDRAM. So just keep the + default values: + CONFIG_DRAM_BASE = 0x40000000 + CONFIG_DRAM_SIZE = 0x04000000 = SZ_64M + +config SKIP_DUMP_CPU_INFO + bool + default y + help + ARM9TDMI cores do not support cache size + recognition instructions which use MMU features. + +config P2001_WATCHDOG + bool 'P2001 watchdog timer support' + default y + help + Activate P2001 watchdog timer with reset in idle function. + +config P2001_TIMER2_LED_FREQ_INDICATOR + bool 'P2001 timer2 led frequency indicator' + default y + help + Use timer2 interrupt to blink leds with 10 Hz at 73.728 MHz. + Lower SYSCLK scales down blinking as well. + +endmenu + +endif diff --git a/arch/arm/mach-p2001/Makefile b/arch/arm/mach-p2001/Makefile new file mode 100644 index 00000000..26f47f42 --- /dev/null +++ b/arch/arm/mach-p2001/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o time.o + +obj-$(CONFIG_CPU_FREQ_P2001) += p2001_cpufreq.o diff --git a/arch/arm/mach-p2001/Makefile.boot b/arch/arm/mach-p2001/Makefile.boot new file mode 100644 index 00000000..a2cd824f --- /dev/null +++ b/arch/arm/mach-p2001/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x40100000 +params_phys-y := 0x40500000 +initrd_phys-y := 0x40600000 diff --git a/arch/arm/mach-p2001/arch.c b/arch/arm/mach-p2001/arch.c new file mode 100644 index 00000000..b41a18f6 --- /dev/null +++ b/arch/arm/mach-p2001/arch.c @@ -0,0 +1,94 @@ +/* + * linux/arch/arm/mach-p2001/arch.c + * + * Copyright (C) 2004-2005 Tobias Lorenz + * + * uClinux kernel startup code for p2001 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void __init p2001_init_irq(void); +extern struct sys_timer p2001_timer; + +#ifdef CONFIG_P2001_AUTO_DETECT_SDRAM +/* automatic memory detection (by write tests at each memory banks) */ +static void __init p2001_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) +{ + volatile char *mem_start; // bank 0 + volatile char *mem_end; // bank n + char mem_wrap; // value of bank 0 + char mem_err; // value of bank n + + /* save memstart */ + mem_start = (char *) CONFIG_DRAM_BASE; + mem_wrap = *mem_start; + + /* search wrap or error position */ + for(mem_end = mem_start + SZ_1M; mem_end < (char *) (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE); mem_end += SZ_1M) { + mem_err = *mem_end; + (*mem_end)++; + if (mem_err+1 != *mem_end) + break; + if (mem_wrap != *mem_start) + break; + *mem_end = mem_err; + } + *mem_end = mem_err; + + /* print message */ + printk("Auto detected SDRAM: 0x%08x - 0x%08x (size: %dMB)\n", + (unsigned int) mem_start, (unsigned int) mem_end, + ((unsigned int) mem_end - (unsigned int) mem_start) / SZ_1M); + + /* give values to mm */ + mi->nr_banks = 1; + mi->bank[0].start = (unsigned int) mem_start; + mi->bank[0].size = (unsigned int) mem_end - (unsigned int) mem_start; + mi->bank[0].node = 0; +} +#endif + +MACHINE_START(P2001, "P2001") + /* Maintainer: Tobias Lorenz */ +#ifdef CONFIG_P2001_AUTO_DETECT_SDRAM + .fixup = p2001_fixup, +#endif + .init_irq = p2001_init_irq, + .timer = &p2001_timer, +MACHINE_END diff --git a/arch/arm/mach-p2001/entry-macro.S b/arch/arm/mach-p2001/entry-macro.S new file mode 100644 index 00000000..7b0a0f91 --- /dev/null +++ b/arch/arm/mach-p2001/entry-macro.S @@ -0,0 +1,168 @@ +/* + * linux/arch/armnommu/mach-p2001/entry-macro.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + * 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 + +#define Adr_INT_CTRL_BASE 0x00130000 +#define REL_Adr_Main_NFIQ_Int_Ctrl 0x00 +#define REL_Adr_Main_NIRQ_Int_Ctrl 0x04 +#define REL_Adr_Status_NFIQ 0x08 +#define REL_Adr_Status_NIRQ 0x0c + +#define NR_IRQS 27 /* 27 Interrupts: INT 0..26 */ + + + /* disable FIQ */ + .macro disable_fiq + .endm + + + /* + * get the irq number(at least), and others. + * irqnr : The number of the IRQ that you want to raise. + * irqstat: ??? + * base : The comments suggest this is a prioritization mechanism, but it doesn't appear + * to be actually used anywhere. That's why many of the irq_prio_table macros are empty. + * flags : This is non-obvious, but you'll notice that every get_irqnr_and_base macro + * does a test at the end of the macro. If you don't have a flag (I think it's the Z) set, + * then you'll never call do_IRQ. It's basically a check to avoid calling do_IRQ if you had + * a spurious interrupt (or one that was masked). + */ + /* irqnr=r0 irqstat=r6 base=r5 tmp=lr */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov \irqstat, #Adr_INT_CTRL_BASE + ldr \irqstat, [\irqstat, #REL_Adr_Status_NIRQ] + + mov \irqnr, #IRQ_EU0_DATA + tst \irqstat, #(1< +#include + +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + * --------------------------- + * + * This is normally called from the decompressor code. The requirements + * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, + * r1 = machine nr. + * + * See linux/arch/arm/tools/mach-types for the complete list of machine + * numbers for r1. + * + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r0, #0 + ldr r1, P2001_MACH_TYPE + + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + ldr r9, P2001_PROCESSOR_TYPE + +/* + * Set the Control Register and Read the process ID. + */ + mov r0, #0 + +/* + * r0 = processor control register + * r1 = machine ID + * r9 = processor ID + * r12 = value of r0 when kernel was called (currently always zero) + */ + adr r5, LC0 + ldmia r5, {r5, r6, r7, r8, sp} @ Setup stack + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r7 + strcc r4, [r5],#4 + bcc 1b + + str r9, [r6] @ Save processor ID + str r1, [r8] @ Save machine type + + b start_kernel + +LC0: .long __bss_start @ r5 + .long processor_id @ r6 + .long _end @ r7 + .long __machine_arch_type @ r8 + .long init_thread_union+8192 @ sp + +/* + * arm_id/PROCESSOR_TYPE: + * 31:24: Implementer (ARM Ltd) + * 23:20: Variant (0) + * 19:16: Architecture (4T) + * 15:4: Primary Part Number (0) + * 3:0 Revision (0) + */ +P2001_PROCESSOR_TYPE: + .long 0x41029000 +P2001_MACH_TYPE: + .long MACH_TYPE_P2001 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-p2001/irq.c b/arch/arm/mach-p2001/irq.c new file mode 100644 index 00000000..21c7e3d7 --- /dev/null +++ b/arch/arm/mach-p2001/irq.c @@ -0,0 +1,164 @@ +/* + * linux/arch/arm/mach-p2001/irq.c + * + * Copyright (C) 2004-2005 Tobias Lorenz + * + * IRQ handling code + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +/************************************************************************** + * IRQ Chip + **************************************************************************/ + +void __inline__ p2001_irqchip_mask(unsigned int irq) +{ + unsigned long mask = 1 << (irq); + P2001_INT_CTRL->Main_NIRQ_Int_Ctrl &= ~mask; +} + +void __inline__ p2001_irqchip_unmask(unsigned int irq) +{ + unsigned long mask = 1 << (irq); + P2001_INT_CTRL->Main_NIRQ_Int_Ctrl |= mask; +} + +void __inline__ p2001_irqchip_ack(unsigned int irq) +{ + p2001_irqchip_mask(irq); +} + +#if 0 +int __inline__ p2001_irqchip_retrigger(unsigned int irq) +{ + /* not implemented */ + return 0; +} +#endif + +#if 0 +int __inline__ p2001_irqchip_type(unsigned int irq, unsigned int flags) +{ + /* not implemented */ + return 0; +} +#endif + +#if 0 +int __inline__ p2001_irqchip_wake(unsigned int irq, unsigned int on) +{ + /* not implemented */ + return 0; +} +#endif + +static struct irqchip p2001_irqchip = { + .ack = p2001_irqchip_ack, /* Acknowledge the IRQ. */ + .mask = p2001_irqchip_mask, /* Mask the IRQ in hardware. */ + .unmask = p2001_irqchip_unmask, /* Unmask the IRQ in hardware. */ +// .retrigger = p2001_irqchip_retrigger, /* Ask the hardware to re-trigger the IRQ. */ +// .type = p2001_irqchip_type, /* Set the type of the IRQ. */ +// .wake = p2001_irqchip_wake, /* Set wakeup-enable on the selected IRQ */ +}; + + + +/************************************************************************** + * System IRQ Device/Class + **************************************************************************/ + +#if 0 +static int irq_shutdown(struct sys_device *dev) +{ + return 0; +} +#endif + +#ifdef CONFIG_PM +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#endif + +static struct sysdev_class irq_class = { +// .shutdown = irq_shutdown, +#ifdef CONFIG_PM + .suspend = irq_suspend, + .resume = irq_resume, +#endif + set_kset_name("irq"), +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + + + +/************************************************************************** + * Module functions + **************************************************************************/ + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init p2001_init_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &p2001_irqchip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } +} diff --git a/arch/arm/mach-p2001/p2001_cpufreq.c b/arch/arm/mach-p2001/p2001_cpufreq.c new file mode 100644 index 00000000..4ef9b7ab --- /dev/null +++ b/arch/arm/mach-p2001/p2001_cpufreq.c @@ -0,0 +1,286 @@ +/* + * linux/arch/arm/mach-p2001/p2001_cpufreq.c + * + * Copyright (C) 2004-2005 Tobias Lorenz + * + * CPU frequency scaling support + * + * 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. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct cpufreq_driver p2001_cpufreq_driver; + +static int p2001_cpufreq_driver_init(struct cpufreq_policy *policy); +static int p2001_cpufreq_driver_verify(struct cpufreq_policy *policy); +//static int p2001_cpufreq_driver_setpolicy(struct cpufreq_policy *policy); +static int p2001_cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); +static unsigned int p2001_cpufreq_driver_get(unsigned int cpu); + +static struct cpufreq_frequency_table p2001_cpufreq_frequency_table[] = +{ + /* index is also the scaling factor */ + // 6 kHz (minimum) + { .index = 1, .frequency = 12288 }, // 12.288 MHz (no network) + { .index = 2, .frequency = 24576 }, // 24.576 MHz (no network) + { .index = 3, .frequency = 36864 }, // 36.864 MHz + { .index = 4, .frequency = 49152 }, // 49.152 MHz + { .index = 5, .frequency = 61440 }, // 61.440 MHz + { .index = 6, .frequency = 73728 }, // 73.728 MHz + { .index = 7, .frequency = 86016 }, // 86.016 MHz (overclocked) + { .index = 8, .frequency = 98304 }, // 98.304 MHz (overclocked) + { .index = 9, .frequency = 110592 }, // 110.592 MHz (not working) + { .frequency = CPUFREQ_TABLE_END }, +}; + +static int p2001_cpufreq_driver_init(struct cpufreq_policy *policy) +{ +// printk("p2001_cpufreq_driver_init\n"); + + /* set default policy and cpuinfo */ + if (policy->cpu != 0) + return -EINVAL; + + policy->cur = policy->min = policy->max = p2001_cpufreq_driver_get(policy->cpu); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.max_freq = 73728; // kHz + policy->cpuinfo.min_freq = 36864; // kHz + policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ + + return 0; +} + +/** + * p2001_cpufreq_driver_verify - verifies a new CPUFreq policy + * @policy: new policy + * + * Limit must be within this model's frequency range at least one + * border included. + */ +static int p2001_cpufreq_driver_verify(struct cpufreq_policy *policy) +{ +// printk("p2001_cpufreq_driver_verify\n"); + return cpufreq_frequency_table_verify(policy, p2001_cpufreq_frequency_table); +} + +/** + * p2001_cpufreq_driver_verify - set a new CPUFreq policy + * @policy: new policy + * + * Sets a new CPUFreq policy. + */ +/* +static int p2001_cpufreq_driver_setpolicy(struct cpufreq_policy *policy) +{ +// printk("p2001_cpufreq_driver_setpolicy\n"); + // what to do here ? + return 0; +} +*/ + +/** + * p2001_cpufreq_driver_target - set a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * Sets a new CPUFreq policy. + */ +static int p2001_cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + struct cpufreq_freqs freqs; + unsigned int M, P, S, N, PWRDN; // PLL_12288_config + unsigned int M_DIV, N_DIV, SEL_PLL, SEL_DIV; // DIV_12288_config + unsigned int config; + +// printk("p2001_cpufreq_driver_target(target_freq=%d)\n", target_freq); + if (cpufreq_frequency_table_target(policy, &p2001_cpufreq_frequency_table[0], target_freq, relation, &newstate)) + return -EINVAL; + + freqs.old = p2001_cpufreq_driver_get(policy->cpu); + freqs.new = p2001_cpufreq_frequency_table[newstate].frequency; + freqs.cpu = 0; /* p2001_cpufreq.c is UP only driver */ + + if (freqs.new == freqs.old) + return 0; +// printk("System clock change from %d kHz to %d kHz\n", freqs.old, freqs.new); + + M = 0; + S = 0; + P = 0; + N = 0; + PWRDN = 0; + M_DIV = 1; + N_DIV = newstate; + SEL_PLL = 1; + SEL_DIV = 0; + switch (p2001_cpufreq_frequency_table[newstate].index) { + case 1: // 12288 kHz + PWRDN = 1; + SEL_PLL = 0; + break; + case 2: // 24576 kHz + P = 2; + break; + case 3: // 36864 kHz + M = 1; + P = 1; + break; + case 4: // 49152 kHz + M = 0; + break; + case 5: // 61440 kHz + M = 2; + break; + case 6: // 73728 kHz + M = 4; + break; + case 7: // 86016 kHz + M = 6; + break; + case 8: // 98304 kHz + M = 8; + break; + case 9: // 110592 kHz + M = 10; + break; + } + + /* notifier */ + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* change DIV first to bypass PLL before PWRDN */ + config = (M_DIV<<0) | (N_DIV<<8) | (SEL_PLL<<16) | (SEL_DIV<<17); + P2001_TIMER->DIV_12288_config = config; + config = (M<<0) | (P<<8) | (S<<14) | (N<<16) | (PWRDN<<26); + P2001_TIMER->PLL_12288_config = config; + + /* notifier */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +/* + * returns current frequency in kHz + */ +static unsigned int p2001_cpufreq_driver_get(unsigned int cpu) +{ + cpumask_t cpus_allowed; + unsigned int current_freq; + unsigned int M, P, S, N, PWRDN; // PLL_12288_config + unsigned int M_DIV, N_DIV, SEL_PLL, SEL_DIV; // DIV_12288_config + +// printk("p2001_cpufreq_driver_get\n"); + /* + * Save this threads cpus_allowed mask. + */ + cpus_allowed = current->cpus_allowed; + + /* + * Bind to the specified CPU. When this call returns, + * we should be running on the right CPU. + */ + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(cpu != smp_processor_id()); + + /* get current setting */ + M = (P2001_TIMER->PLL_12288_config >> 0) & 0x00ff; + P = (P2001_TIMER->PLL_12288_config >> 8) & 0x003f; + S = (P2001_TIMER->PLL_12288_config >> 14) & 0x0003; + N = (P2001_TIMER->PLL_12288_config >> 16) & 0x03ff; + PWRDN = (P2001_TIMER->PLL_12288_config >> 26) & 0x0001; + M_DIV = (P2001_TIMER->DIV_12288_config >> 0) & 0x00ff; + N_DIV = (P2001_TIMER->DIV_12288_config >> 8) & 0x00ff; + SEL_PLL = (P2001_TIMER->DIV_12288_config >> 16) & 0x0001; + SEL_DIV = (P2001_TIMER->DIV_12288_config >> 17) & 0x0001; +// printk("M=%d P=%d S=%d N=%d PWRDN=%d\n", M, P, S, N, PWRDN); +// printk("M_DIV=%d N_DIV=%d SEL_PLL=%d SEL_DIV=%d\n", M_DIV, N_DIV, SEL_PLL, SEL_DIV); + + current_freq = 12288; // External 12.288 MHz oscillator +// printk("cpufreq after OSC: %d\n", current_freq); + + switch (SEL_PLL) { + case 0: // shortcut + break; + case 1: // PLL + /* WARNING: 2^S=2 for S=0 (CodeSourcery ARM Q1A 2004) */ +// current_freq *= PWRDN ? 0 : ((M+8) / ( (2^S) * (P+2) )); // correct + current_freq *= PWRDN ? 0 : ((M+8) / (P+2)); // working + break; + case 2: // 0 + current_freq = 0; + break; + } +// printk("cpufreq after PLL: %d\n", current_freq); + + switch (SEL_DIV) { + case 0: // shortcut + break; + case 1: + current_freq /= (2*(N+1)); + break; + } +// printk("cpufreq after DIV: %d\n", current_freq); + + /* + * Restore the CPUs allowed mask. + */ + set_cpus_allowed(current, cpus_allowed); + + return current_freq; +} + +static struct cpufreq_driver p2001_cpufreq_driver = { + .name = "P2001 cpufreq", + .init = p2001_cpufreq_driver_init, + .verify = p2001_cpufreq_driver_verify, +// .setpolicy = p2001_cpufreq_driver_setpolicy, + .target = p2001_cpufreq_driver_target, + .get = p2001_cpufreq_driver_get, +}; + +static int __init p2001_cpufreq_module_init(void) +{ +// printk("p2001_cpufreq_module_init\n"); + return cpufreq_register_driver(&p2001_cpufreq_driver); +} + +static void __exit p2001_cpufreq_module_exit(void) +{ +// printk("p2001_cpufreq_module_exit\n"); + cpufreq_unregister_driver(&p2001_cpufreq_driver); +} + +module_init(p2001_cpufreq_module_init); +module_exit(p2001_cpufreq_module_exit); + +MODULE_AUTHOR("Tobias Lorenz"); +MODULE_DESCRIPTION("P2001 cpu frequency scaling driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-p2001/time.c b/arch/arm/mach-p2001/time.c new file mode 100644 index 00000000..a331b544 --- /dev/null +++ b/arch/arm/mach-p2001/time.c @@ -0,0 +1,273 @@ +/* + * linux/arch/arm/mach-p2001/time.c + * + * Copyright (C) 2004-2005 Tobias Lorenz + * + * Timer handling code + * + * 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. + * + * 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 +#include +#include +#include + +#ifdef CONFIG_CPU_FREQ +#include +#include +#endif + +#include +#include +#include +#include + +#include + +#define P2001_TIMER_VALUE(reg, mask, shift, value) { \ + unsigned int i = (P2001_TIMER->reg); \ + i &= ~((mask) << (shift)); \ + i |= (((value) & (mask)) << (shift)); \ + (P2001_TIMER->reg) = i; \ +} + +/* + * short calculation + * --------------------------------------------------------------- + * prescaler = factor * (SYSCLK / 12288000) max: 255 + * period = SYSCLK/prescaler/HZ max: 65535 + * clocks_per_usec = SYSCLK/prescaler / 1000000 min: 1 + * = 12288000 / factor / 1000000 + * --------------------------------------------------------------- + * IMPORTANT: recalculate factor when HZ changes, so that limits + * are kept within SYSCLK range (12288000-73728000) + */ + +/************************************************************************** + * Timer 1: Scheduler + **************************************************************************/ +#define TIMER1_HZ HZ /* 100-1000 HZ */ +#define TIMER1_FACTOR 2 + +static irqreturn_t p2001_timer1_interrupt(int irq, void *dev_id) +{ + write_seqlock(&xtime_lock); + + timer_tick(); + + /* clear interrupt pending bit */ + P2001_TIMER->TIMER_INT &= ~(1<<0); // Timer1_Int + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction p2001_timer1_irq = { + .name = "P2001 timer1", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = p2001_timer1_interrupt, +}; + +/* Return number of microseconds since last interrupt */ +#define TIMER1_CLOCKS_PER_USEC (12288000/TIMER1_FACTOR/1000000) +static unsigned long p2001_gettimeoffset(void) +{ + return ((0xffff - P2001_TIMER->Timer1) & 0xffff) / TIMER1_CLOCKS_PER_USEC; +} + +#ifdef CONFIG_CPU_FREQ +/* + * Transistion notifier + */ +static int p2001_timer1_notifier(struct notifier_block *self, unsigned long phase, void *data) +{ + struct cpufreq_freqs *cf = data; + unsigned int prescaler, period; + + if ((phase == CPUFREQ_POSTCHANGE) || + (phase == CPUFREQ_RESUMECHANGE)) { + prescaler = TIMER1_FACTOR*cf->new/12288; + period = (1000*cf->new/prescaler)/TIMER1_HZ; + P2001_TIMER_VALUE(TIMER_PRELOAD, 0xffff, 0, period); + P2001_TIMER_VALUE(Timer12_PreDiv, 0xff, 0, prescaler - 1); + } + + return NOTIFY_OK; +} + +static struct notifier_block p2001_timer1_nb = { &p2001_timer1_notifier, NULL, 0 }; +#endif /* CONFIG_CPU_FREQ */ + +static void p2001_timer1_init(void) +{ + unsigned int prescaler, period; + + /* initialize the timer period and prescaler */ + prescaler = TIMER1_FACTOR*(CONFIG_SYSCLK/12288000); + period = (CONFIG_SYSCLK/prescaler)/TIMER1_HZ; + P2001_TIMER_VALUE(TIMER_PRELOAD, 0xffff, 0, period); + P2001_TIMER_VALUE(Timer12_PreDiv, 0xff, 0, prescaler - 1); + + /* set up the interrupt vector for timer 1 match */ + setup_irq(IRQ_TIMER1, &p2001_timer1_irq); + + /* enable the timer IRQ */ + P2001_TIMER->TIMER_INT |= (1<<4); // Timer1_Int_En + + /* let timer 1 run... */ + P2001_TIMER->Timer12_PreDiv &= ~(1<<28); // Timer_1_Disable + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&p2001_timer1_nb, CPUFREQ_TRANSITION_NOTIFIER); +#endif +} + + +/************************************************************************** + * Timer 2: LED Frequency Indicator + **************************************************************************/ +#ifdef CONFIG_P2001_TIMER2_LED_FREQ_INDICATOR +#define TIMER2_HZ 10 +#define TIMER2_FACTOR 20 + +static irqreturn_t p2001_timer2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int gpio2; + + /* switch leds */ + gpio2 = P2001_GPIO->GPIO2_Out; + if (gpio2 & 0x0040) { + /* gpio23_v4 on */ + gpio2 &= ~0x00c0; + gpio2 |= 0x0080; + } else { + /* gpio22_v5 on */ + gpio2 &= ~0x00c0; + gpio2 |= 0x0040; + } + P2001_GPIO->GPIO2_Out = gpio2; + + /* clear interrupt pending bit */ + P2001_TIMER->TIMER_INT &= ~(1<<1); // Timer2_Int + + return IRQ_HANDLED; +} + +static struct irqaction p2001_timer2_irq = { + .name = "P2001 timer2", + .flags = SA_INTERRUPT, + .handler = p2001_timer2_interrupt, +}; + +static void p2001_timer2_init(void) +{ + unsigned int prescaler, period; + + /* initialize the timer period and prescaler */ + prescaler = TIMER2_FACTOR*(CONFIG_SYSCLK/12288000); + period = (CONFIG_SYSCLK/prescaler)/TIMER2_HZ; + P2001_TIMER_VALUE(TIMER_PRELOAD, 0xffff, 16, period); + P2001_TIMER_VALUE(Timer12_PreDiv, 0xff, 8, prescaler - 1); + + /* Activate Leds Frequency Indicator */ + /* Schematics say that: SDO_2/GPIO_22=V5, SDI_2/GPIO_23=V4 */ + P2001_GPIO->PIN_MUX |= (1<<2); // set MUX to GPIOs + P2001_GPIO->GPIO2_En |= 0xC0; // Enable GPIO driver + P2001_GPIO->GPIO2_Out |= 0x00C00000; // Mask bits + + /* set up the interrupt vector for timer 2 match */ + setup_irq(IRQ_TIMER2, &p2001_timer2_irq); + + /* enable the timer IRQ */ + P2001_TIMER->TIMER_INT |= (1<<5); // Timer2_Int_En + + /* let timer 2 run... */ + P2001_TIMER->Timer12_PreDiv &= ~(1<<29); // Timer_2_Disable +} +#endif + + +/************************************************************************** + * Watchdog + **************************************************************************/ +#ifdef CONFIG_P2001_WATCHDOG +static irqreturn_t p2001_wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + // printk(KERN_CRIT "Critical watchdog value reached: %d!\n", P2001_TIMER->WatchDog_Timer); + + /* Reset watchdog */ + P2001_TIMER->Timer12_PreDiv |= (1<<31); // WatchDog_Reset + + /* clear interrupt pending bit */ + P2001_TIMER->TIMER_INT &= ~(1<<2); // WatchDog_Int + + return IRQ_HANDLED; +} + +static struct irqaction p2001_wdt_irq = { + .name = "P2001 watchdog", + .flags = SA_INTERRUPT, + .handler = p2001_wdt_interrupt, +}; + +static void p2001_wdt_init(void) +{ + /* Set predivider, so that watchdog runs at 3000 Hz */ + /* Reset after 65536/3000 = 21.85 secs (75 MHz) */ + P2001_TIMER->Timer12_PreDiv |= (0xfff << 16); // PreDiv_WatchDog + + /* Reset watchdog */ + P2001_TIMER->Timer12_PreDiv |= (1<<31); // WatchDog_Reset + + /* Warning after 30000/3000 = 10 secs passed */ + P2001_TIMER->TIMER_INT |= (1<<6); // WatchDog_Int_En + P2001_TIMER->TIMER_INT &= 0xff; // WatchDog_Int_Level + P2001_TIMER->TIMER_INT |= (30000 << 8); // WatchDog_Int_Level + + /* Activate watchdog warning interrupt */ + setup_irq(IRQ_WATCHDOG, &p2001_wdt_irq); + + /* Activate watchdog */ + P2001_TIMER->Timer12_PreDiv &= ~(1<<30); // WatchDog_Disable +} +#endif + + +/************************************************************************** + * Main init + **************************************************************************/ +static void __init p2001_init_time(void) +{ + /* + * disable and clear timer 0, set to + * internal clock and interval mode + */ + P2001_TIMER->Timer12_PreDiv = 0x70bb0000; + P2001_TIMER->Timer1 = 0; + P2001_TIMER->Timer2 = 0; + + p2001_timer1_init(); +#ifdef CONFIG_P2001_TIMER2_LED_FREQ_INDICATOR + p2001_timer2_init(); +#endif +#ifdef CONFIG_P2001_WATCHDOG + p2001_wdt_init(); +#endif +} + +struct sys_timer p2001_timer = { + .init = p2001_init_time, + .offset = p2001_gettimeoffset, +}; diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index d6601336..53965a9a 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -88,4 +88,4 @@ obj-$(CONFIG_MACH_OTOM) += mach-otom.o obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o -obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file +obj-$(CONFIG_MACH_SMDK) += common-smdk.o diff --git a/arch/arm/mach-s3c24a0/Kconfig b/arch/arm/mach-s3c24a0/Kconfig new file mode 100644 index 00000000..3f317e8c --- /dev/null +++ b/arch/arm/mach-s3c24a0/Kconfig @@ -0,0 +1,13 @@ +if ARCH_S3C24A0 + +menu "S3C24A0 Implementations" + +config ARCH_SMDK24A0 + bool "Meritek SMDK24A0" + +config ARCH_SPJ + depends on ARCH_SMDK24A0 + bool "Bluetek SPJ Daughter Board for SMDK24A0" +endmenu + +endif diff --git a/arch/arm/mach-s3c24a0/Makefile b/arch/arm/mach-s3c24a0/Makefile new file mode 100644 index 00000000..d6f5f264 --- /dev/null +++ b/arch/arm/mach-s3c24a0/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux kernel. +# Copyright (C) 2005, Hyok S. Choi +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + + +obj-y := +obj-m := registers.o +obj-n := +obj- := + +# for MMU enabled kernel, needs mapping codes +obj-$(CONFIG_MMU) += generic.o + +# Common support (must be linked before board specific support) +obj-y += irq.o clocks.o time.o + +# Specific board support +obj-$(CONFIG_ARCH_SMDK24A0) += smdk.o + +# LEDs support +leds-y := leds.o +leds-$(CONFIG_ARCH_SMDK24A0) += leds-smdk.o +obj-$(CONFIG_LEDS) += $(leds-y) + diff --git a/arch/arm/mach-s3c24a0/Makefile.boot b/arch/arm/mach-s3c24a0/Makefile.boot new file mode 100644 index 00000000..8842bf95 --- /dev/null +++ b/arch/arm/mach-s3c24a0/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x10008000 +params_phys-y := 0x10000100 +initrd_phys-y := 0x10800000 diff --git a/arch/arm/mach-s3c24a0/clocks.c b/arch/arm/mach-s3c24a0/clocks.c new file mode 100644 index 00000000..3dee63b7 --- /dev/null +++ b/arch/arm/mach-s3c24a0/clocks.c @@ -0,0 +1,117 @@ +/* + * arch/arm/mach-s3c24a0/clocks.c + * + * $Id: clocks.c,v 1.3 2006/12/12 13:38:48 gerg Exp $ + * + * 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 +#include +#include + +#include +#include + + + +static unsigned long get_usb_clk_freq(int who) +{ + unsigned long val = UPLLCON; + + if (CLKSRC & (1<<7)) return 0; /* UPLL OFF */ + val = ((GET_MDIV(val) + 8) * FIN)/((GET_PDIV(val) + 2) * (1 << GET_SDIV(val))); + return val; +} + +/* + * CLKDIVN differs from S3C24A0X to S3C24A0A + * --SW.LEE + */ + +static inline unsigned long +cal_bus_clk(unsigned long cpu_clk, unsigned long ratio, int who) +{ + unsigned long hclk = 0; + unsigned long pclk = 0; + + if (who == GET_UPLL) + return get_usb_clk_freq(GET_UPLL); + + switch (ratio & 0x6) { + case 0: + hclk = cpu_clk; + break; + case 2: + hclk = cpu_clk/2; + break; + case 4: + hclk = cpu_clk/4; + break; + default: + panic("Wrong Value in CLKDIVN"); + } + switch (ratio & 0x1) { + case 0: + pclk = hclk; + break; + case 1: + pclk = hclk/2; + break; + } + + if (who == GET_HCLK) + return hclk; + else { + if (who == GET_PCLK) + return pclk; + else + panic("Wrong Clock requested "); + } +} + + +/* + * cpu clock = (((mdiv + 8) * FIN) / ((pdiv + 2) * (1 << sdiv))) + * FIN = Input Frequency (to CPU) + */ +unsigned long +elfin_get_cpu_clk(void) +{ + unsigned long val = MPLLCON; + + return (((GET_MDIV(val) + 8) * FIN) / ((GET_PDIV(val) + 2) * (1 << GET_SDIV(val)))); +} +EXPORT_SYMBOL(elfin_get_cpu_clk); + +unsigned long +elfin_get_bus_clk(int who) +{ + unsigned long cpu_clk = elfin_get_cpu_clk(); + unsigned long ratio = CLKDIVN_BUS; + + return (cal_bus_clk(cpu_clk, ratio, who)); +} +EXPORT_SYMBOL(elfin_get_bus_clk); + +#define MEGA (1000 * 1000) +static int __init elfin_cpu_init(void) +{ + unsigned long freq, hclk, pclk; + + freq = elfin_get_cpu_clk(); + hclk = elfin_get_bus_clk(GET_HCLK); + pclk = elfin_get_bus_clk(GET_PCLK); + + printk(KERN_INFO "CPU clock = %ld.%03ld Mhz,", freq / MEGA, freq % MEGA); + + printk(" HCLK = %ld.%03ld Mhz, PCLK = %ld.%03ld Mhz\n", + hclk / MEGA, hclk % MEGA, pclk / MEGA, pclk % MEGA); + + return 0; +} + +__initcall(elfin_cpu_init); diff --git a/arch/arm/mach-s3c24a0/generic.c b/arch/arm/mach-s3c24a0/generic.c new file mode 100644 index 00000000..ec421ca9 --- /dev/null +++ b/arch/arm/mach-s3c24a0/generic.c @@ -0,0 +1,41 @@ +/* + * /arch/arm/mach-s3c24a0/generic.c + * + * $Id: generic.c,v 1.3 2006/12/12 13:38:48 gerg Exp $ + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* + * Common I/O mapping: + * + * 0x4000.0000 ~ 0x4Aff.fffff + (0xe000.0000 ~ 0xeAff.fffff) GPIO + */ +static struct map_desc standard_io_desc[] __initdata = { + /* virtual physical length */ + { 0xe0000000, 0x40000000, 0x10000000, MT_DEVICE}, +}; + +void __init elfin_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} diff --git a/arch/arm/mach-s3c24a0/generic.h b/arch/arm/mach-s3c24a0/generic.h new file mode 100644 index 00000000..c4fca99c --- /dev/null +++ b/arch/arm/mach-s3c24a0/generic.h @@ -0,0 +1,14 @@ +/* + * /arch/arm/mach-s3c24a0/generic.h + * + * $Id: generic.h,v 1.2 2005/11/28 03:55:09 gerg Exp $ + * + * 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. + */ +extern void __init elfin_map_io(void); +extern void __init elfin_init_irq(void); + +/* drivers/serial/serial_s3c24a0.c */ +extern void __init elfin_register_uart(int idx, int port); diff --git a/arch/arm/mach-s3c24a0/head.S b/arch/arm/mach-s3c24a0/head.S new file mode 100644 index 00000000..d48f2c8e --- /dev/null +++ b/arch/arm/mach-s3c24a0/head.S @@ -0,0 +1,172 @@ +/* + * linux/arch/armnommu/mach-s3c24a0/head.S + * + * Taken from mach-s5c7375/head.S + * + * modified by heechul.yun@samsung.com + */ + +#include +#include + +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + +/* + * ARM920T need MMU enable for D-cache. + * we just make the identical table before the MMU enabling. + */ +#ifdef CONFIG_CPU_MXU_ENABLE + /* Write domain id (cp15_r3) */ + mvn r0, #0 /* Domains 0, 1 = client */ + mcr p15, 0, r0, c3, c0, 0 /* load domain access register */ + /* Set control register v4 */ + + mov r0, #0 + mcr p15, 0, r0, c13, c0, 0 /* zero PID */ + mcr p15, 0, r0, c7, c7, 0 /* invalidate I,D caches */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate I,D TLBs */ + mrc p15, 0, r0, c1, c0, 0 /* get control register */ + bic r0, r0, #0x0001 /* disable MMU */ + mcr p15, 0, r0, c1, c0, 0 /* write control register */ + + +init_ttb: + /* + * We must reserve DRAM_BASE ~ DRAM_BASE+0x8000. + * And Kernel TEXTADDR must be after DRAM_BASE + 0x8000 + */ +#if !defined(CONFIG_DRAM_BASE) || !defined(CONFIG_DRAM_SIZE) + #define CONFIG_DRAM_BASE 0x10000000 + #define CONFIG_DRAM_SIZE 0x04000000 +#endif + ldr r0,=(CONFIG_DRAM_BASE + 0x4000) /* set TTB (Must be on 16KB boundary) */ + mcr p15, 0, r0, c2, c0, 0 /* write to TTB(CP15,c2) */ + + /* + * + * Create translation table for flat mapping + * Top 12 bits of VA is pointer into table + * Create 4096 entries from 000xxxxx to fffxxxxx + * + * Set Section descriptor. 4K entry totla and + * each entry describe 1MB. + */ + mov r1, #0x1000 @ 4K counter + subs r1,r1,#1 + mov r2,#0b110000000000 @ set access permissions (AP) for full access SVC/USR (11:10) + orr r2,r2,#0b000111100000 @ set for domain 15 (8:5) + orr r2,r2,#0b000000010000 @ must be 1 (4) + orr r2,r2,#0b000000000000 @ set non cachable non bufferable (CB) (3:2) + orr r2,r2,#0b000000000010 @ set for 1Mb section (1:0) +init_ttb_1: /* create 4K entry */ + orr r3,r2,r1,lsl#20 @ use loop counter to create individual table entries + str r3,[r0,r1,lsl#2] @ str r3 at TTB base + loopcount*4 + subs r1,r1,#1 @ decrement loop counter + bpl init_ttb_1 + + /* resetting the SDRAM area to cacheable*/ + /* DRAM_BASE ~ DRAM_BASE+DRAM_SIZE */ + /* 64MB -> 64 entry -> 0x40 */ + mov r1, #(CONFIG_DRAM_SIZE >> 20 ) @ 64 entry =ase addr + subs r1, r1, #1 + + mov r2,#0b110000000000 @ set access permissions (AP) for full access SVC/USR (11:10) + orr r2,r2,#0b000111100000 @ set for domain 15 (8:5) + orr r2,r2,#0b000000010000 @ must be 1 (4) + orr r2,r2,#0b000000001100 @ set cachable but unbufferable (CB) (3:2) + orr r2,r2,#0b000000000010 @ set for 1Mb section (1:0) + +init_ttb_2: /* create 64 entry (for 64MB SDRAM) */ + add r4, r1, #(CONFIG_DRAM_BASE >> 20 ) @ drambase >> 20 bit . + orr r3,r2,r4,lsl#20 @ use loop counter to create individual table entries + str r3,[r0,r4,lsl#2] @ str r3 at TTB base + loopcount*4 + subs r1,r1,#1 @ decrement loop counter + bpl init_ttb_2 + @init_domains : we define all domains are manager. so no access permission check is occured. + mvn r0, #0 @ trick. 0 -1 == 0xFFFFFFFF + mcr p15, 0, r0, c3, c0, 0 @ write to CP15 register 5 +/* + * set global core configurations + */ + mrc p15, 0, r0, c1, c0, 0 @ read CP15 register 1 into r0 + +#ifndef CONFIG_CPU_ICACHE_DISABLE + orr r0, r0, #(0x1 <<12) @ enable I Cache +#endif +#ifndef CONFIG_CPU_DCACHE_DISABLE + orr r0, r0, #(0x1 <<2) @ enable D Cache +#endif +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #2 @ ...........A. +#endif + orr r0, r0, #(0b11 <<30) @ enable asynchronous clocking mode + orr r0, r0, #0x1 @ enable MMU + + mcr p15, 0, r0, c1, c0, 0 @ write cp15 register 1 + +#endif + +/* + * stuffs for cache are done. + * Now we setup the stack and machine id, and start the kernel! + */ + + adr r5, LC0 + ldmia r5, {r5, r6, r7, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + ldr r2, S3C24A0_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, S3C24A0_MACH_TYPE + str r2, [r9] + + str r0, [r7] /* save c1 to cr_alignment */ + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start @ r5 + .long processor_id @ r6 + .long cr_alignment @ r7 + .long _end @ r8 + .long __machine_arch_type @ r9 + .long init_thread_union+8192 @ sp + +S3C24A0_PROCESSOR_TYPE: + .long 0x41069264 +S3C24A0_MACH_TYPE: + .long MACH_TYPE_S3C24A0 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-s3c24a0/irq.c b/arch/arm/mach-s3c24a0/irq.c new file mode 100644 index 00000000..37a40ec5 --- /dev/null +++ b/arch/arm/mach-s3c24a0/irq.c @@ -0,0 +1,313 @@ +/*$)C + * arch/arm/mach-s3c24a0/irq.c + * + * Generic S3C24A0 IRQ handling. + * + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +/* Pendng registers + * + * INTPND 0x40200010 + * SUBINTPND 0x40200018 + * EINTPND 0x44800038 + */ +static const unsigned long p_regs[3] = { 0x40200010, 0x40200018, 0x44800038 }; + +/* Mask registers + * + * INTMSK 0x40200008 + * SUBINTMSK 0x4020001c + * EINTMSK 0x44800034 + */ + +static const unsigned long m_regs[3] = { 0x40200008, 0x4020001c, 0x44800034 }; + +/* + * Interrupt table + */ +static const int r_irqs[NR_IRQS] = { + 96, 96, 96, 96, 96, 5, 6, 7, 8, 9, 10, 11, 12, 96, 96, 15, + 96, 96, 18, 19, 96, 21, 22, 96, 96, 25, 26, 27, 96, 29, 30, 96, + 17, 17, 17, 23, 23, 23, 28, 28, 96, 96, 96, 13, 13, 16, 16, 14, + 14, 31, 31, 31, 14, 24, 24, 29, 29, 20, 20, 20, 20, 96, 96, 96, + 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 +}; + +static inline void clear_pending(int irq) +{ + int i = r_irqs[irq]; + if (i == NR_IRQS) + return; + + *(volatile unsigned long *)(io_p2v(p_regs[irq >> 5])) = (1 << (irq % 32)); + SRCPND = (1 << i); + INTPND = INTPND; + INTPND; +} + +static inline int read_pending(int irq) +{ + return ((*(volatile unsigned long *)(io_p2v(p_regs[irq >> 5]))) & (1 << (irq % 32))); +} + +static inline void mask_irq(int irq) +{ + *(volatile unsigned long *)(io_p2v(m_regs[irq >> 5])) |= (1 << (irq % 32)); +} + +static inline void unmask_irq(int irq) +{ + *(volatile unsigned long *)(io_p2v(m_regs[irq >> 5])) &= ~(1 << (irq % 32)); +} + +//#define DEBUG // hcyun +#undef DEBUG + +static inline int find_irq(int irq) +{ + int i; + +#ifdef DEBUG + if ( irq == 4 || irq == 3 ) printk("find_irq: irq=%d\n", irq); +#endif + + for (i = IRQ_GRP1_START; i < NR_IRQS; i++) { + if (r_irqs[i] == irq) { +#ifdef DEBUG + if ( i >= 64 ) printk("Externel IRQ %d\n", i); + else if ( i >= 32 ) printk("Sub IRQ %d\n", i); +#endif + + if (read_pending(i)) { +#ifdef DEBUG + if ( i >= 64 ) printk("OK there's external pending IRQ %d\n", i); + else if ( i >= 32 ) printk("OK there's sub pending IRQ %d\n", i); +#endif + return i; + } + } + } + return NR_IRQS; +} + +int fixup_irq(int irq) +{ + int retval = NR_IRQS; + + if (irq >= IRQ_GRP1_START) + return retval; + + if ((r_irqs[irq]) == NR_IRQS) { + retval = find_irq(irq); + } else { + retval = irq; + } + + return retval; +} + +static void elfin_mask_ack_irq(unsigned int irq) +{ + mask_irq(irq); + clear_pending(irq); +} + +static void elfin_ack_irq(unsigned int irq) +{ + clear_pending(irq); +} + +static void elfin_mask_irq(unsigned int irq) +{ + mask_irq(irq); +} + +static void elfin_unmask_irq(unsigned int irq) +{ + unmask_irq(irq); +} + +static struct irqchip s3c24a0_irq_chip = { + .ack = elfin_ack_irq, // irq_ack + .mask = elfin_mask_irq, // irq_mask + .unmask = elfin_unmask_irq // irq_unmak +}; + + + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct sysdev_class irq_class = { + set_kset_name("irq"), + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init elfin_init_irq(void) +{ + int irq; + + unsigned int flags; + + /* disable all interrupts */ + INTSUBMSK = 0xffffffff; + EINTMASK = 0xffffffff; + INTMSK = 0xffffffff; + + /* clear status registers */ + EINTPEND = EINTPEND; + SUBSRCPND = SUBSRCPND; + SRCPND = SRCPND; + INTPND = INTPND; + + /* all interrupts set as IRQ */ + INTMOD = 0x00000000; + + /* we have three groups */ + for (irq = 0; irq < NR_IRQS; irq++) { + flags = IRQF_PROBE; + + /* external IRQ */ + if ((r_irqs[irq]) == NR_IRQS) { + if (irq < IRQ_GRP1_START) + INTMSK &= ~(1 << irq); + } + /* main IRQ */ + else if ( irq < IRQ_GRP2_START ) + flags |= IRQF_VALID; + + set_irq_chip(irq, &s3c24a0_irq_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, flags); + } +} + +/* + * S3C24A0 , External Interrupt setting interface + * + * 1) GPIO-A8: external irq$)C + * 2) Edge setting + * |<--ECTRL-->|<--GPIO--->| + * bit reg bit reg + * ofs ofs ofs ofs + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * |4-bit|4-bit|4-bit|4-bit|4-bit|4-bit|4-bit|4-bit| + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +static const unsigned long garbage[] = { + 0xffff0000, /* EINT 0 */ + 0xffff1010, /* EINT 1 */ + 0xffff2020, /* EINT 2 */ + 0xffff0130, /* EINT 3 */ + 0xffff1140, /* EINT 4 */ + 0xffff2150, /* EINT 5 */ + 0xffff3160, /* EINT 6 */ + 0xffff4170, /* EINT 7 */ + 0xffff5180, /* EINT 8 */ + 0xffff6190, /* EINT 9 */ + 0xffff71a0, /* EINT 10 */ + 0xffff0201, /* EINT 11 */ + 0xffff1211, /* EINT 12 */ + 0xffff2221, /* EINT 13 */ + 0xffff3231, /* EINT 14 */ + 0xffff4241, /* EINT 15 */ + 0xffff5251, /* EINT 16 */ + 0xffff6261, /* EINT 17 */ + 0xffff7271, /* EINT 18 */ +}; + +int set_external_irq(int irq, int edge, int pullup) +{ + int phy_irq = EINTIRQ_DEC(irq); /* physical irq number */ + unsigned long g; + struct irqdesc *desc; + + + if (phy_irq > 18) + return -EINVAL; + + g = garbage[phy_irq]; + + /* GPIO setting */ + *(volatile unsigned long *)(io_p2v(0x44800008 - (0x4 * (g & 0x0000000f)))) &= ~(0x3 << (((g & 0x000000f0) >> 0x4) * 0x2)); + *(volatile unsigned long *)(io_p2v(0x44800008 - (0x4 * (g & 0x0000000f)))) |= (0x2 << (((g & 0x000000f0) >> 0x4) * 0x2)); + +#if 0 + printk("GPIO(0x%x) = 0x%x\n", io_p2v(0x44800008), *(volatile unsigned long *)io_p2v(0x44800008)); + printk("GPIO(0x%x) = 0x%x\n", io_p2v(0x44800004), *(volatile unsigned long *)io_p2v(0x44800004)); +#endif + + /* edge setting */ + *(volatile unsigned long *)(io_p2v(0x44800018 + (0x4 * ((g & 0x00000f00) >> 0x8)))) &= ~(0x7 << (((g & 0x0000f000) >> 0xc) * 0x4)); + *(volatile unsigned long *)(io_p2v(0x44800018 + (0x4 * ((g & 0x00000f00) >> 0x8)))) |= (edge << (((g & 0x0000f000) >> 0xc) * 0x4)); + + /* Set pullup */ + GPUP &= ~(1 << phy_irq); + GPUP |= pullup; + + desc = irq_desc + irq; + desc->valid = 1; + + switch ( edge ) { + case EINT_FALLING_EDGE: + case EINT_RISING_EDGE: + case EINT_BOTH_EDGES: + set_irq_handler(irq, do_edge_IRQ); + break; + case EINT_LOW_LEVEL: + case EINT_HIGH_LEVEL: + set_irq_handler(irq, do_level_IRQ); + break; + } + clear_pending(irq); + return 0; +} + +EXPORT_SYMBOL(set_external_irq); diff --git a/arch/arm/mach-s3c24a0/leds-smdk.c b/arch/arm/mach-s3c24a0/leds-smdk.c new file mode 100644 index 00000000..0f3d35a4 --- /dev/null +++ b/arch/arm/mach-s3c24a0/leds-smdk.c @@ -0,0 +1,121 @@ +/* + * arch/arm/mach-s3c24a0/leds-smdk.c + * + * $Id: leds-smdk.c,v 1.3 2006/12/12 13:38:48 gerg Exp $ + * + * 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 + +#include +#include +#include +#include + +#include "leds.h" + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +#define LED0 (1 << 0) +#define LED1 (1 << 1) +#define LED2 (1 << 2) +#define LED3 (1 << 3) + +static unsigned int led_state; +static unsigned int hw_led_state; + +static inline void +led_update(unsigned int state) +{ + write_gpio_bit(SMDK_LED4, (state & LED0)); + write_gpio_bit(SMDK_LED5, ((state & LED1) >> 1)); + write_gpio_bit(SMDK_LED6, ((state & LED2) >> 2)); + write_gpio_bit(SMDK_LED7, ((state & LED3) >> 3)); +} + +void +smdk_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state = (LED1 | LED2 | LED3); + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + hw_led_state = (LED0 | LED1 | LED2 | LED3); + led_update(hw_led_state); + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = (LED0 | LED1 | LED2 | LED3); + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = (LED1 | LED2 | LED3); + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED3; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED2; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED2; + break; +#endif + + case led_halted: + break; + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED2; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED2; + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + break; + + case led_red_off: + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + led_update(hw_led_state); + + local_irq_restore(flags); +} diff --git a/arch/arm/mach-s3c24a0/leds.c b/arch/arm/mach-s3c24a0/leds.c new file mode 100644 index 00000000..da3e721b --- /dev/null +++ b/arch/arm/mach-s3c24a0/leds.c @@ -0,0 +1,30 @@ +/* + * /arch/arm/mach-s3c24a0/leds.c + * + * $Id: leds.c,v 1.2 2005/11/28 03:55:09 gerg Exp $ + * + * 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 + +#include +#include + +#include "leds.h" + +static int __init +s3c24a0_leds_init(void) +{ +#ifdef CONFIG_BOARD_SMDK24A0 + if (machine_is_s3c24a0()) + leds_event = smdk_leds_event; +#endif + + leds_event(led_start); + return 0; +} + +__initcall(s3c24a0_leds_init); diff --git a/arch/arm/mach-s3c24a0/leds.h b/arch/arm/mach-s3c24a0/leds.h new file mode 100644 index 00000000..1337f117 --- /dev/null +++ b/arch/arm/mach-s3c24a0/leds.h @@ -0,0 +1,7 @@ +/* + * arch/arm/mach-s3c24a0/leds.h + * + * $Id: leds.h,v 1.2 2005/11/28 03:55:09 gerg Exp $ + * + */ +extern void smdk_leds_event(led_event_t evt); diff --git a/arch/arm/mach-s3c24a0/registers.c b/arch/arm/mach-s3c24a0/registers.c new file mode 100644 index 00000000..cb03bd47 --- /dev/null +++ b/arch/arm/mach-s3c24a0/registers.c @@ -0,0 +1,261 @@ +/* + * arch/arm/mach-s3c24a0/register.c + * + * S3C24A0 register monitor & controller + * + * $Id: registers.c,v 1.3 2006/12/12 13:38:48 gerg Exp $ + * + * 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. + */ + +#include +#include /* because we are a module */ +#include /* for the __init macros */ +#include /* all the /proc functions */ +#include +#include /* to copy to/from userspace */ +#include + +#define MODULE_NAME "regmon" +#define CPU_DIRNAME "cpu" +#define REG_DIRNAME "registers" + +static ssize_t proc_read_reg(struct file * file, char * buf, + size_t nbytes, loff_t *ppos); +static ssize_t proc_write_reg(struct file * file, const char * buffer, + size_t count, loff_t *ppos); + +static struct file_operations proc_reg_operations = { + read: proc_read_reg, + write: proc_write_reg +}; + +typedef struct elfin_reg_entry { + u32 phyaddr; + char* name; + unsigned short low_ino; +} elfin_reg_entry_t; + +static elfin_reg_entry_t elfin_regs[] = +{ +/* { phyaddr, name } */ + + /* PLL clock */ + {0x40000000, "LOCKTIME"}, + {0x40000004, "OSCWEST"}, + {0x40000010, "MPLLCON"}, + {0x40000014, "UPLLCON"}, + {0x40000020, "CLKCON"}, + {0x40000024, "CLKSRC"}, + {0x40000028, "CLKDIV"}, + {0x40000030, "PWRMAN"}, + {0x40000038, "SOFTRESET"}, + + /* INT */ + {0x40200000, "SRCPND"}, + {0x40200004, "INTMOD"}, + {0x40200008, "INTMSK"}, + {0x4020000c, "PRIORITY"}, + {0x40200010, "INTPND"}, + {0x40200014, "INTOFFSET"}, + {0x40200018, "SUBSRCPND"}, + {0x4020001c, "INTSUBMSK"}, + {0x40200020, "VECINTMOD"}, + {0x40200024, "VECADDR"}, + {0x40200028, "NVECADDR"}, + {0x4020002c, "VAR"}, + + /* SROM */ + {0x40c20000, "SROM_BW"}, + {0x40c20004, "SROM_BC0"}, + {0x40c20008, "SROM_BC1"}, + {0x40c2000c, "SROM_BC2"}, + + /* PWM timer */ + {0x44000000, "TCFG0"}, + {0x44000004, "TCFG1"}, + {0x44000008, "TCON"}, + {0x4400000c, "TCNTB0"}, + {0x44000010, "TCMPB0"}, + {0x44000014, "TCNTO0"}, + {0x44000018, "TCNTB1"}, + {0x4400001c, "TCMPB1"}, + {0x44000020, "TCNTO1"}, + {0x44000024, "TCNTB2"}, + {0x44000028, "TCMPB2"}, + {0x4400002c, "TCNTO2"}, + {0x44000030, "TCNTB3"}, + {0x44000034, "TCMPB3"}, + {0x44000038, "TCNTO3"}, + {0x4400003c, "TCNTB4"}, + {0x44000040, "TCNTO4"}, + + /* CamIF */ + {0x48000004, "CAM_STAY1"}, + {0x48000008, "CAM_STAY2"}, + {0x4800000c, "CAM_STAY3"}, + {0x48000010, "CAM_STAY4"}, + {0x48000000, "CAM_RDSTAT"}, + + /* Post Processor */ + {0x4a100000, "VP_MODE"}, + {0x4a100004, "VP_RATIO_Y"}, + {0x4a100008, "VP_RATIO_CB"}, + {0x4a10000c, "VP_RATIO_CR"}, + {0x4a100010, "VP_SRC_WIDTH"}, + {0x4a100014, "VP_SRC_HEIGHT"}, + {0x4a100018, "VP_DST_WIDTH"}, + {0x4a10001c, "VP_DST_HEIGHT"}, + {0x4a100020, "VP_START_Y1"}, + {0x4a100024, "VP_START_Y2"}, + {0x4a100028, "VP_START_Y3"}, + {0x4a10002c, "VP_START_Y4"}, + {0x4a100030, "VP_START_CB1"}, + {0x4a100034, "VP_START_CB2"}, + {0x4a100038, "VP_START_CB3"}, + {0x4a10003c, "VP_START_CB4"}, + {0x4a100040, "VP_START_CR1"}, + {0x4a100044, "VP_START_CR2"}, + {0x4a100048, "VP_START_CR3"}, + {0x4a10004c, "VP_START_CR4"}, + {0x4a100050, "VP_START_RGB1"}, + {0x4a100054, "VP_START_RGB2"}, + {0x4a100058, "VP_START_RGB3"}, + {0x4a10005c, "VP_START_RGB4"}, + {0x4a100060, "VP_END_Y1"}, + {0x4a100064, "VP_END_Y2"}, + {0x4a100068, "VP_END_Y3"}, + {0x4a10006c, "VP_END_Y4"}, + {0x4a100070, "VP_END_CB1"}, + {0x4a100074, "VP_END_CB2"}, + {0x4a100078, "VP_END_CB3"}, + {0x4a10007c, "VP_END_CB4"}, + {0x4a100080, "VP_END_CR1"}, + {0x4a100084, "VP_END_CR2"}, + {0x4a100088, "VP_END_CR3"}, + {0x4a10008c, "VP_END_CR4"}, + {0x4a100090, "VP_END_RGB1"}, + {0x4a100094, "VP_END_RGB2"}, + {0x4a100098, "VP_END_RGB3"}, + {0x4a10009c, "VP_END_RGB4"}, + {0x4a1000f0, "VP_BYPASS"}, + {0x4a1000f4, "VP_OFS_Y"}, + {0x4a1000f8, "VP_OFS_CB"}, + {0x4a1000fc, "VP_OFS_CR"}, + {0x4a100100, "VP_OFS_RGB"}, + + /* BUS matrix */ + {0x40ce0000, "BUS_PRIORITY0"}, + {0x40ce0004, "BUS_PRIORITY1"}, +}; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +static int proc_read_reg(struct file * file, char * buf, + size_t nbytes, loff_t *ppos) +{ + int i_ino = (file->f_dentry->d_inode)->i_ino; + char outputbuf[15]; + int count; + int i; + elfin_reg_entry_t* current_reg=NULL; + if (*ppos>0) /* Assume reading completed in previous read*/ + return 0; + for (i=0;iphyaddr))); + *ppos+=count; + if (count>nbytes) /* Assume output can be read at one time */ + return -EINVAL; + if (copy_to_user(buf, outputbuf, count)) + return -EFAULT; + return count; +} + +static ssize_t proc_write_reg(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + int i_ino = (file->f_dentry->d_inode)->i_ino; + elfin_reg_entry_t* current_reg=NULL; + int i; + unsigned long newRegValue; + char *endp; + + for (i=0;iphyaddr))=newRegValue; + return (count+endp-buffer); +} + +static struct proc_dir_entry *regdir; +static struct proc_dir_entry *cpudir; + +static int __init init_reg_monitor(void) +{ + struct proc_dir_entry *entry; + int i; + + cpudir = proc_mkdir(CPU_DIRNAME, &proc_root); + if (cpudir == NULL) { + printk(KERN_ERR MODULE_NAME": can't create /proc/" CPU_DIRNAME "\n"); + return(-ENOMEM); + } + + regdir = proc_mkdir(REG_DIRNAME, cpudir); + if (regdir == NULL) { + printk(KERN_ERR MODULE_NAME": can't create /proc/" CPU_DIRNAME "/" REG_DIRNAME "\n"); + return(-ENOMEM); + } + + for(i=0;ilow_ino; + entry->proc_fops = &proc_reg_operations; + } else { + printk( KERN_ERR MODULE_NAME + ": can't create /proc/" REG_DIRNAME + "/%s\n", elfin_regs[i].name); + return(-ENOMEM); + } + } + return (0); +} + +static void __exit cleanup_reg_monitor(void) +{ + int i; + for(i=0;i update for 2.6.10 + * 2004/06/10 Initial CPLD IDE support for SPJ + * 2004/06/13 CPLD IDE and USB csupport for SPJ + * 2004/06/23 Added bank1 access functions and now + * IDE works with cs8900. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "generic.h" + +// #define DEBUG; +#ifdef DEBUG +# define PDEBUG(fmt, args...) \ +printk(KERN_DEBUG "[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) +#else +# define PDEBUG(fmt, args...) do {} while(0) +#endif + +/* global lock to protect bank1 register settings */ +spinlock_t bank1_lock = SPIN_LOCK_UNLOCKED; + +bank_param_t bank1_params[] = +{ + { 0x08, 0x3740 }, /* B1_IDE_PIO0 */ + { 0x08, 0x2340 }, /* B1_IDE_PIO4 */ + { 0x38, 0x3740 }, /* B1_CS89x0 */ + { 0x00, 0x2200 }, /* B1_USB2 */ +}; + +/* bank1 state of interrupt context */ +static int b1_int_state = B1_STATE_NONE; + +/** + * real_bank1_set_param: blah blah + */ +static __inline__ void real_bank1_set_param(int bw_val, int bc1_val) +{ + SROM_BW &= ~0x38; + SROM_BW |= bw_val; + SROM_BC1 = bc1_val; +} + +/** + * bank1_set_state - set bank1 timing + * @state - state + * + * long description + */ +void bank1_set_state(int state) +{ +#if 0 + unsigned long flags; + + if ( state == B1_STATE_NONE) + return; + + if ( state > B1_STATE_LIMIT || state < B1_STATE_NONE ) + panic("bank1: Inavlid state"); + + + spin_lock_irqsave( &bank1_lock, flags); + + if ( !in_interrupt()) + current->bank1_state = state; + + real_bank1_set_param( bank1_params[state].bw, bank1_params[state].bc); + + spin_unlock_irqrestore( &bank1_lock, flags); +#endif + +} + + +void bank1_set_int_state(int state) +{ +#if 0 + unsigned long flags; + + if ( !in_interrupt() ) + panic("bank1_set_int_state is called fron interrupt context\n"); + + spin_lock_irqsave( &bank1_lock, flags); + + b1_int_state = state; /* set */ + + if ( state == B1_STATE_NONE) /* 1st level interrupt */ + state = current->bank1_state; + + if ( state != B1_STATE_NONE ) + real_bank1_set_param( bank1_params[state].bw, bank1_params[state].bc); + + spin_unlock_irqrestore( &bank1_lock, flags); +#endif +} + +/* + * bank1_get_int_state - bank1 state of interrupt context + */ +int bank1_get_int_state(void) +{ + return b1_int_state; +} + +EXPORT_SYMBOL(bank1_set_state); +EXPORT_SYMBOL(bank1_set_int_state); +EXPORT_SYMBOL(bank1_get_int_state); + +static int __init smdk_init(void) +{ + printk("%s: initialize smdk24a0 board\n", __func__); + + set_gpio_ctrl(SMDK_LED4 | GPIO_PULLUP_DIS | GPIO_MODE_OUT); + set_gpio_ctrl(SMDK_LED5 | GPIO_PULLUP_DIS | GPIO_MODE_OUT); + set_gpio_ctrl(SMDK_LED6 | GPIO_PULLUP_DIS | GPIO_MODE_OUT); + set_gpio_ctrl(SMDK_LED7 | GPIO_PULLUP_DIS | GPIO_MODE_OUT); + +/* + // real_bank1_set_param(0x38, 0x3740); + real_bank1_set_param(0x38, 0x2340); +*/ + real_bank1_set_param( bank1_params[B1_CS89x0].bw, bank1_params[B1_CS89x0].bc); + printk("Set BANK1 register (0x%x, 0x%x)\n", SROM_BW, SROM_BC1); + + return 0; +} + +__initcall(smdk_init); + +#ifdef CONFIG_MMU +/* + * I/O mapping: + */ +static struct map_desc smdk_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { SMDK_CS8900_VIO, SMDK_CS8900_PIO, SZ_1M, MT_DEVICE}, + { SMDK_CPLD_IDE_VIO, SMDK_CPLD_IDE_PIO, 0x00900000, MT_DEVICE}, // hcyun + { SMDK_CPLD_USB_VIO, SMDK_CPLD_USB_PIO, 0x00900000, MT_DEVICE}, // hcyun +}; + +static void __init smdk_map_io(void) +{ + elfin_map_io(); // 0x4000.0000 -> 0xe000.0000 +} +#endif /* CONFIG_MMU */ + +static void __init fixup_smdk(struct machine_desc *desc, + struct tag *tags, char **cmdline, struct meminfo *mi) +{ +#ifdef CONFIG_MMU + iotable_init(smdk_io_desc, ARRAY_SIZE(smdk_io_desc)); +#endif +#ifdef CONFIG_SERIAL_S3C24A0 + elfin_register_uart(0, 0); +#endif +#ifdef CONFIG_PM + register_wakeup_src(0, EINT_RISING_EDGE, 0); +#endif + +} + + +#include + +extern void elfin_time_init(void); +extern unsigned long elfin_gettimeoffset(void); + +extern void __init elfin_init_irq(void); + +extern struct sys_timer elfin_timer; + + + +MACHINE_START(S3C24A0, "Samsung-SMDK24A0") + /* Maintainer: Hyok S. Choi */ +#ifdef CONFIG_MMU + .phys_ram = 0x10000000, + .phys_io = 0x40000000, + .io_pg_offst = ((io_p2v (0xe0000000))>>18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = smdk_map_io, +#else + .phys_ram = 0x10000000, + .phys_io = 0x40000000, +#endif + .fixup = fixup_smdk, + .init_irq = elfin_init_irq, + .timer = &elfin_timer, +MACHINE_END diff --git a/arch/arm/mach-s3c24a0/time.c b/arch/arm/mach-s3c24a0/time.c new file mode 100644 index 00000000..8384aa7c --- /dev/null +++ b/arch/arm/mach-s3c24a0/time.c @@ -0,0 +1,248 @@ +/* + * time.c for smdk24a0 + * by Hyok S. Choi + * + * 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 linux/include/asm-arm/arch-s3c2410/time.h + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* copy from linux/arch/arm/kernel/time.c */ +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +#ifndef RTC_LEAP_YEAR +#define RTC_LEAP_YEAR 2000 +#endif + +extern spinlock_t rtc_lock; + +unsigned long elfin_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + + spin_lock_irq(&rtc_lock); +read_rtc_bcd_time: + year = BCDYEAR & Msk_RTCYEAR; + mon = BCDMON & Msk_RTCMON; + day = BCDDAY & Msk_RTCDAY; + hour = BCDHOUR & Msk_RTCHOUR; + min = BCDMIN & Msk_RTCMIN; + sec = BCDSEC & Msk_RTCSEC; + if (sec == 0) { + /* If BCDSEC is zero, reread all bcd registers. + See Section 17.2 READ/WRITE REGISTERS for more info. */ + goto read_rtc_bcd_time; + } + spin_unlock_irq(&rtc_lock); + + BCD_TO_BIN(year); + BCD_TO_BIN(mon); + BCD_TO_BIN(day); + BCD_TO_BIN(hour); + BCD_TO_BIN(min); + BCD_TO_BIN(sec); + + year += RTC_LEAP_YEAR; + + return (mktime(year, mon, day, hour, min, sec)); +} + +/* + * Copyed from drivers/char/sa1100-rtc.c. + */ +#define epoch 1970 + +static const unsigned char days_in_mo[] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +#ifndef is_leap +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* + * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. + */ +static void decodetime (unsigned long t, struct rtc_time *tval) +{ + unsigned long days, month, year, rem; + + days = t / 86400; + rem = t % 86400; + tval->tm_hour = rem / 3600; + rem %= 3600; + tval->tm_min = rem / 60; + tval->tm_sec = rem % 60; + tval->tm_wday = (4 + days) % 7; + +#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) + + year = epoch; + while (days >= (365 + is_leap(year))) { + unsigned long yg = year + days / 365; + days -= ((yg - year) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (year - 1)); + year = yg; + } + tval->tm_year = year - 1900; + tval->tm_yday = days + 1; + + month = 0; + if (days >= 31) { + days -= 31; + month++; + if (days >= (28 + is_leap(year))) { + days -= (28 + is_leap(year)); + month++; + while (days >= days_in_mo[month]) { + days -= days_in_mo[month]; + month++; + } + } + } + tval->tm_mon = month; + tval->tm_mday = days + 1; +} + +int elfin_set_rtc(void) +{ + unsigned long current_time = xtime.tv_sec; + unsigned char year, mon, day, hour, min, sec; + signed int yeardiff; + struct rtc_time rtc_tm; + + decodetime(current_time, &rtc_tm); + + yeardiff = (rtc_tm.tm_year + 1900) - RTC_LEAP_YEAR; + if (yeardiff < 0) { + /* S3C2410 RTC forces that the year must be higher or + equal than 2000, so initailize it. */ + yeardiff = 0; + } + + year = (unsigned char) yeardiff; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hour = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(year); + + spin_lock_irq(&rtc_lock); + RTCCON |= RTCCON_EN; + BCDSEC = sec & Msk_RTCSEC; + BCDMIN = min & Msk_RTCMIN; + BCDHOUR = hour & Msk_RTCHOUR; + BCDDAY = day & Msk_RTCDAY; + BCDMON = mon & Msk_RTCMON; + BCDYEAR = year & Msk_RTCYEAR; + RTCCON &= ~RTCCON_EN; + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static unsigned long elfin_gettimeoffset(void) +{ + unsigned long elapsed, usec; + unsigned long latch; + + /* Use TCNTB4 as LATCH */ + latch = TCNTB4; + + elapsed = latch - TCNTO4; + usec = (elapsed * (tick_nsec / 1000)) / latch; // hcyun + + return usec; +} + +static irqreturn_t elfin_timer_interrupt(int irq, void *dev_id) +{ + +// do_set_rtc(); + timer_tick(); + + return IRQ_HANDLED; + +} + +static struct irqaction elfin_timer_irq = { + .name = "S3C24A0 Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = elfin_timer_interrupt +}; + +#define TCON4_PRESCALER_VALUE 15 +#define TCON4_DIVIDER_VALUE 2 +#define TCON4_PERIOD 10 /* miliseconds */ +void __init elfin_time_init(void) +{ + set_rtc = elfin_set_rtc; + xtime.tv_sec = elfin_get_rtc_time(); + + /* set timer interrupt */ + TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(TCON4_PRESCALER_VALUE) | TCFG0_PRE0(TCON4_PRESCALER_VALUE)); + + /* + * period = (prescaler value + 1) * (divider value) * buffer count / PCLK + * buffer count = period * PCLK / divider value / (prescaler value + 1) + * + * e.g.) + * + * PCLK = 50700000 Hz, divider value = 2, prescaler value = 15 + * period = 10ms + * + * buffer count = ((10 / 1000) * 50700000) / 2 / (15+1) + * = 15843.75 + */ + + printk("DEBUG: PCLK=%d, Prescaler=%d, Divider=%d\n", elfin_get_bus_clk(GET_PCLK), TCON4_PRESCALER_VALUE+1, TCON4_DIVIDER_VALUE ); + TCNTB4 = ((TCON4_PERIOD * ((elfin_get_bus_clk(GET_PCLK))/1000)) / TCON4_DIVIDER_VALUE) / (TCON4_PRESCALER_VALUE + 1); + printk("DEBUG: timer count %d\n", TCNTB4); + + TCON = (TCON_4_AUTO | TCON_4_UPDATE | (0 << 20)); + + elfin_timer_irq.handler = elfin_timer_interrupt; + + printk("Timer Initialized.. IRQ=%d\n", IRQ_TIMER4); + + setup_irq(IRQ_TIMER4, &elfin_timer_irq); + + TCON = (TCON_4_AUTO | (0 << 21) | TCON_4_ONOFF); +} + +struct sys_timer elfin_timer = { + .init = elfin_time_init, + .offset = elfin_gettimeoffset, +}; + +EXPORT_SYMBOL(elfin_get_rtc_time); +EXPORT_SYMBOL(elfin_set_rtc); diff --git a/arch/arm/mach-s3c3410/Kconfig b/arch/arm/mach-s3c3410/Kconfig new file mode 100644 index 00000000..e1c51878 --- /dev/null +++ b/arch/arm/mach-s3c3410/Kconfig @@ -0,0 +1,33 @@ +menu "S3C3410 Options" + depends on ARCH_S3C3410 + +config ARCH_SUPPORTS_BIG_ENDIAN + bool + default y + help + S3C3410 core supports BIG-ENDIAN only, + both for CPU core and the external memory access. + +config ARM_CLK + int 'Arm Core Clock' + default 40000000 + help + the default host clock of SMDK40100 is 40MHz. + otherwise, change the value in clock. + +config SKIP_DUMP_CPU_INFO + bool + default y + help + S3C3410(ARM7TDMI) core does not support cache size + recognition instructions which uses MMU features. + +config REMAP_VECTORS_TO_RAM + bool + default y + help + S3C3410 core does not support ROM and RAM remap + function. we set the trap_init to be initialized + at the begining of DRAM_BASE. + +endmenu diff --git a/arch/arm/mach-s3c3410/Makefile b/arch/arm/mach-s3c3410/Makefile new file mode 100644 index 00000000..41084302 --- /dev/null +++ b/arch/arm/mach-s3c3410/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o mm.o dma.o time.o diff --git a/arch/arm/mach-s3c3410/arch.c b/arch/arm/mach-s3c3410/arch.c new file mode 100644 index 00000000..cd9ff597 --- /dev/null +++ b/arch/arm/mach-s3c3410/arch.c @@ -0,0 +1,54 @@ +/* + * linux/arch/arm/mach-s5c7375/arch.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +extern void __init s3c3410_init_irq(void); +extern void s3c3410_time_init(void); + +static void __init +fixup_s3c3410(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +} + +MACHINE_START(S3C3410, "S3C3410, SAMSUNG ELECTRONICS Co., Ltd.") + MAINTAINER("Hyok S. Choi ") + FIXUP(fixup_s3c3410) + INITIRQ(s3c3410_init_irq) + INITTIME(s3c3410_time_init) +MACHINE_END diff --git a/arch/arm/mach-s3c3410/dma.c b/arch/arm/mach-s3c3410/dma.c new file mode 100644 index 00000000..3a991dae --- /dev/null +++ b/arch/arm/mach-s3c3410/dma.c @@ -0,0 +1,26 @@ +/* + * arch/arm/arch-s3c3410/dma.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co., Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void arch_dma_init(dma_t *dma) +{ +} diff --git a/arch/arm/mach-s3c3410/head.S b/arch/arm/mach-s3c3410/head.S new file mode 100644 index 00000000..16dc42e4 --- /dev/null +++ b/arch/arm/mach-s3c3410/head.S @@ -0,0 +1,69 @@ +/* + * linux/arch/arm/mach-s3c3410/head.S + * + * Copyright (C) 2003 Hyok S. Choi + * + * + * uClinux kernel startup code for s3c3410 + * which has no proper bootloader for linux startup + */ +#include +#include + +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + ldr r2, S3C3410_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, S3C3410_MACH_TYPE + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + +S3C3410_PROCESSOR_TYPE: + .long 0x34107700 +S3C3410_MACH_TYPE: + .long MACH_TYPE_S3C3410 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-s3c3410/irq.c b/arch/arm/mach-s3c3410/irq.c new file mode 100644 index 00000000..a33c6855 --- /dev/null +++ b/arch/arm/mach-s3c3410/irq.c @@ -0,0 +1,130 @@ +/* + * linux/arch/arm/mach-s5c7375/irq.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * based the codes by + * 2003 Thomas Eschenbacher + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +void __inline__ s3c3410_mask_irq(unsigned int irq) +{ + outl( inl(S3C3410X_INTMSK) & ~( 1 << irq ), S3C3410X_INTMSK); +} + +void __inline__ s3c3410_unmask_irq(unsigned int irq) +{ + outl( inl(S3C3410X_INTMSK) | ( 1 << irq ), S3C3410X_INTMSK); +} + +void __inline__ s3c3410_mask_ack_irq(unsigned int irq) +{ + s3c3410_mask_irq(irq); +} + +/* Clear pending bit */ +void __inline__ s3c3410_clear_pb(unsigned int irq) +{ + outl( ~(1 << irq), S3C3410X_INTPND);} + + +/* YOU CAN CHANGE THIS ROUTINE FOR SPEED UP */ +__inline__ unsigned int fixup_irq (int irq ) +{ + s3c3410_clear_pb(irq); + return(irq); +} + +static struct irqchip s3c3410_chip = { + .ack = s3c3410_clear_pb, + .mask = s3c3410_mask_irq, + .unmask = s3c3410_unmask_irq, +}; + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(struct sys_device *dev, u32 state) +{ + return 0; +} + +static int irq_resume(struct sys_device *dev) +{ + /* disable all irq sources */ + return 0; +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct sysdev_class irq_class = { + set_kset_name("irq"), + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); + +void __init s3c3410_init_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &s3c3410_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* mask and disable all further interrupts */ + outl(0x00000000, S3C3410X_INTMSK); + + /* set all to IRQ mode, not FIQ */ + outl(0x00000000, S3C3410X_INTMOD); + + /* Clear Intrerrupt pending register */ + outl(0x00000000, S3C3410X_INTPND); + + /* + * enable the gloabal interrupt flag, this should be + * safe now, all sources are masked out and acknowledged + */ + outb(inb(S3C3410X_SYSCON) | S3C3410X_SYSCON_GIE, S3C3410X_SYSCON); +} + diff --git a/arch/arm/mach-s3c3410/mm.c b/arch/arm/mach-s3c3410/mm.c new file mode 100644 index 00000000..b7a863e9 --- /dev/null +++ b/arch/arm/mach-s3c3410/mm.c @@ -0,0 +1,21 @@ +/* + * linux/arch/armnommu/mach-s3c3410/mm.c + * + * Copyright(C)2003 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +static void __init s3c3410_map_io(void) +{ +} diff --git a/arch/arm/mach-s3c3410/time.c b/arch/arm/mach-s3c3410/time.c new file mode 100644 index 00000000..48da59af --- /dev/null +++ b/arch/arm/mach-s3c3410/time.c @@ -0,0 +1,95 @@ +/* + * linux/arch/armnommu/mach-s3c3410/time.c + * + * Copyright (C) SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +extern void s3c3410_unmask_irq(unsigned int irq); + +unsigned long s3c3410_gettimeoffset (void) +{ + return (inw(S3C3410X_TCNT0) / CLOCKS_PER_USEC); +} + +static irqreturn_t +s3c3410_timer_interrupt(int irq, void *dev_id) +{ + timer_tick(); + + return IRQ_HANDLED; +} + +static struct irqaction s3c3410_timer_irq = { + .name = "S3C3410 Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = s3c3410_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ + +void __init s3c3410_time_init (void) +{ + u_int8_t tmod; + u_int16_t period; + + /* + * disable and clear timer 0, set to + * internal clock and interval mode + */ + tmod = S3C3410X_T16_OMS_INTRV | S3C3410X_T16_CL; + outb(tmod, S3C3410X_TCON0); + + /* initialize the timer period and prescaler */ + period = (CONFIG_ARM_CLK/S3C3410X_TIMER0_PRESCALER)/HZ; + outw(period, S3C3410X_TDAT0); + outb(S3C3410X_TIMER0_PRESCALER-1, S3C3410X_TPRE0); + + /* + * @todo do those really need to be function pointers ? + */ + gettimeoffset = s3c3410_gettimeoffset; + s3c3410_timer_irq.handler = s3c3410_timer_interrupt; + + /* set up the interrupt vevtor for timer 0 match */ + setup_irq(S3C3410X_INTERRUPT_TMC0, &s3c3410_timer_irq); + + /* enable the timer IRQ */ + s3c3410_unmask_irq(S3C3410X_INTERRUPT_TMC0); + + /* let timer 0 run... */ + tmod |= S3C3410X_T16_TEN; + tmod &= ~S3C3410X_T16_CL; + outb(tmod, S3C3410X_TCON0); +} + diff --git a/arch/arm/mach-s3c44b0x/Kconfig b/arch/arm/mach-s3c44b0x/Kconfig new file mode 100644 index 00000000..74e6f515 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/Kconfig @@ -0,0 +1,45 @@ +menu "S3C44B0X Board Options" + depends on ARCH_S3C44B0 + +config DEBUG_NICKMIT + bool 'DEBUG_NICKMIT' + default n + +config SKIP_DUMP_CPU_INFO + bool 'Skip Dump CPU Info' + default y + help + S3C44B0X(ARM7TDMI) core does not support cache size + recognition instructions which uses MMU features. + +config REMAP_VECTORS_TO_RAM + bool 'Remap Vectors To Ram' + default y + help + S3C44B0X core does not support ROM and RAM remap + function. we set the trap_init to be initialized + at the begining of DRAM_BASE. + +config ARM_CLK + int 'Arm Core Clock' + default 60000000 + help + the default host clock of 51EDA-S3C44B0X Board is 60MHz. + otherwise, change the value in clock. + +config ARM_CLK_ADJUST + bool "Arm Core Clock Adjust(EXPERIMENTAL)" + default n && EXPERIMENTAL + help + use this option to adjust the CPU frequence + +config ARM_CLK_FIN + int 'External OSC Clock Frequence' + default 8000000 + depends on ARM_CLK_ADJUST && EXPERIMENTAL + help + this is the input frequence of system clock + +source "arch/arm/mach-s3c44b0x/driver/Kconfig" + +endmenu diff --git a/arch/arm/mach-s3c44b0x/Makefile b/arch/arm/mach-s3c44b0x/Makefile new file mode 100644 index 00000000..dada8266 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o mm.o dma.o time.o cache.o +obj-y += driver/ diff --git a/arch/arm/mach-s3c44b0x/Makefile.boot b/arch/arm/mach-s3c44b0x/Makefile.boot new file mode 100644 index 00000000..2388469c --- /dev/null +++ b/arch/arm/mach-s3c44b0x/Makefile.boot @@ -0,0 +1,2 @@ + zreladdr-y := 0x0c008000 +initrd_phys-y := 0x0c300000 diff --git a/arch/arm/mach-s3c44b0x/arch.c b/arch/arm/mach-s3c44b0x/arch.c new file mode 100644 index 00000000..3cf28b60 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/arch.c @@ -0,0 +1,106 @@ +/* + * linux/arch/arm/mach-s3c44b0x/arch.c + * nickmit_zheng@eastday.com + * based on + * Hyok S. Choi (hyok.choi@samsung.com) + * linux 2.6 armnommu porting + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +// used by sysctl +//#define DEFAULT_MAX_MAP_COUNT 65536 +//int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; + +int s3c44b0x_fMHZ = CONFIG_ARM_CLK / 1000000; +int s3c44b0x_finMHZ = CONFIG_ARM_CLK_FIN / 1000000; + +extern void __init s3c44b0x_init_irq(void); +extern void s3c44b0x_time_init(void); + +void __init s3c44b0x_init_machine(void) +{ +} + +#if CONFIG_DEBUG_NICKMIT +// char my_cmdline[] = "root=/dev/ram rw initrd=0x0c700000,512K"; +char my_cmdline[1024] = "root=/dev/nfs " + "nfsroot=192.168.1.24:/armboot " + "ip=192.168.1.8:192.168.1.24:192.168.1.1:255.255.255.0:arm:eth0:off"; + +void __init change_cmdline(char **cmdline) +{ + int magic_addr[] = {0xcf00000, 0xce000000, 0x1e0000}; + char magic_head[] = "Kernel cmdline:"; + int i; + int cnt = sizeof (magic_addr) / sizeof (int); + char *p, *d; + for(i=0;i") + FIXUP(s3c44b0x_fixup) + INITIRQ(s3c44b0x_init_irq) + INIT_MACHINE(s3c44b0x_init_machine) + INITTIME(s3c44b0x_time_init) +MACHINE_END diff --git a/arch/arm/mach-s3c44b0x/cache.S b/arch/arm/mach-s3c44b0x/cache.S new file mode 100644 index 00000000..0bc59460 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/cache.S @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mm/cache-s3c44b0.S + * + * caution: s3c44b0x DONT have a coprocessor! + */ +#include +#include +#include +#include + +ENTRY(v3_flush_user_cache_all) +ENTRY(v3_flush_kern_cache_all) +ENTRY(v3_flush_user_cache_range) + +ENTRY(v3_coherent_kern_range) + +ENTRY(v3_flush_kern_dcache_page) +ENTRY(v3_dma_inv_range) +ENTRY(v3_dma_flush_range) +ENTRY(v3_dma_clean_range) + mov pc, lr + + __INITDATA + + .type v3_cache_fns, #object +ENTRY(v3_cache_fns) + .long v3_flush_kern_cache_all + .long v3_flush_user_cache_all + .long v3_flush_user_cache_range + .long v3_coherent_kern_range + .long v3_flush_kern_dcache_page + .long v3_dma_inv_range + .long v3_dma_clean_range + .long v3_dma_flush_range + .size v3_cache_fns, . - v3_cache_fns diff --git a/arch/arm/mach-s3c44b0x/dma.c b/arch/arm/mach-s3c44b0x/dma.c new file mode 100644 index 00000000..5628fa56 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/dma.c @@ -0,0 +1,22 @@ +/* + * arch/arm/arch-s3c44b0x/dma.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void arch_dma_init(dma_t *dma) +{ +} diff --git a/arch/arm/mach-s3c44b0x/driver/Kconfig b/arch/arm/mach-s3c44b0x/driver/Kconfig new file mode 100644 index 00000000..12021885 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/Kconfig @@ -0,0 +1,23 @@ +menu "S3C44B0X Board Driver Options" + +config SERIAL_S3C44B0X + bool 'S3C44B0X Serial Support' + default y + help + Samsung S3C44B0X Chips has built-in serial controler + +config SERIAL_S3C44B0X_CONSOLE + bool 'S3C44B0X Serial Console Support' + depends on SERIAL_S3C44B0X + help + use serial port 0 as console + +config ETH_RTL8019AS + bool 'Realtek 8019AS NIC support' + default n + +config S3C44B0X_GPIO_LED + bool 'Use onboard led' + default n + +endmenu diff --git a/arch/arm/mach-s3c44b0x/driver/Makefile b/arch/arm/mach-s3c44b0x/driver/Makefile new file mode 100644 index 00000000..98e3c9c4 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +# obj-$(CONFIG_SERIAL_S3C44B0X) += serial_core_44b0x.o s3c44b0.o +obj-$(CONFIG_SERIAL_S3C44B0X) += console.o +obj-$(CONFIG_ETH_RTL8019AS) += rtl8019.o +obj-$(CONFIG_S3C44B0X_GPIO_LED) += led.o diff --git a/arch/arm/mach-s3c44b0x/driver/console.c b/arch/arm/mach-s3c44b0x/driver/console.c new file mode 100644 index 00000000..78a37b52 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/console.c @@ -0,0 +1,41 @@ +#include +#include +#include + +void s3c44b0x_uart_putc(const char c) +{ + while(!(SYSREG_GET(S3C44B0X_UTRSTAT0) & 0x2)); + SYSREG_SETB(S3C44B0X_UTXH0, c); +} + +void s3c44b0x_console_write(struct console *co, const char *b, unsigned count) +{ + while(count) { + s3c44b0x_uart_putc(*b); + if (*b == '\n') + s3c44b0x_uart_putc('\r'); + ++b; + --count; + } +} + +static int __init s3c44b0x_console_setup(struct console *co, char *options) +{ + return 0; +} + +struct console s3c44b0x_con_driver = { + .name = "S3C44B0X", + .write = s3c44b0x_console_write, + .setup = s3c44b0x_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init s3c44b0x_console_init(void) +{ + register_console(&s3c44b0x_con_driver); + return 0; +} + +console_initcall(s3c44b0x_console_init); diff --git a/arch/arm/mach-s3c44b0x/driver/led.c b/arch/arm/mach-s3c44b0x/driver/led.c new file mode 100644 index 00000000..330291fb --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/led.c @@ -0,0 +1,28 @@ +#include + +void s3c44b0x_led_off(int bit) +{ + SYSREG_OR_SET(S3C44B0X_PDATE, 1<<(4+bit)); +} + +void s3c44b0x_led_on(int bit) +{ + SYSREG_CLR(S3C44B0X_PDATE, 1<<(4+bit)); +} + +void s3c44b0x_led_disp(int data) +{ + data = (data << 12) >> 8; + data = (~data) & 0x1ff; + SYSREG_AND_SET(S3C44B0X_PDATE, ~data); +} + +void s3c44b0x_led_init(void) +{ + SYSREG_AND_SET(S3C44B0X_PCONE, 0xffff556b); + SYSREG_SET(S3C44B0X_PUPE, 0x6); + SYSREG_SET(S3C44B0X_PDATE, 0x3f7); + s3c44b0x_led_disp(15); +} + + diff --git a/arch/arm/mach-s3c44b0x/driver/rtl8019.c b/arch/arm/mach-s3c44b0x/driver/rtl8019.c new file mode 100644 index 00000000..e2766c5e --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/rtl8019.c @@ -0,0 +1,417 @@ +/* + * port to 16bit/8bit remote dma mode lq@cdgwbn.com.cn + * linux/deriver/net/Rtl8019as.c + * Ethernet driver for Samsung 44B0 + * Copyright (C) 2003 antiscle + */ + +#include +#include +#include +#include // kmalloc() +#include // error codes +#include // size_t +#include // mark_bh +#include +#include // net_device +#include +#include +#include +#include +#include +#include +#include "rtl8019.h" + +#define RTL8019_OP_16 1 + +#undef DEBUG +#define DEBUG 1 +#ifdef DEBUG +#define TRACE(str, args...) printk(str, ## args) +#else +#define TRACE(str, args...) +#endif + + +#define outportb(port, data) *((volatile u8 *)(port)) = (u8)(data) +#define inportb(port) *((volatile u8 *)(port)) + + +#define outportw(port, data) *((volatile u16 *)(port)) = (u16)(data) +#define inportw(port) *((volatile u16 *)(port)) + +#define ETH_FRAME_LEN 1514 + +#define RPSTART 0x4c +#define RPSTOP 0x80 +#define SPSTART 0x40 + +static int timeout = 100; // tx watchdog ticks 100 = 1s +static char *version = "Samsung S3C44B0 Rtl8019as driver version 0.1 (2002-02-20) \n"; + +/* + * This structure is private to each device. It is used to pass + * packets in and out, so there is place for a packet + */ +struct nic_8019_priv { + struct net_device_stats stats; + spinlock_t lock; + struct sk_buff *skb; +}; + +/*****************************************************************************/ +static u8 rBNRY; +static u8 SrcMacID[ETH_ALEN] = {0x12,0x34,0x56,0x78,0x90,0xAB,}; + +static void SetRegPage( u8 PageIdx) +{ + u8 temp; + + temp = inportb(BaseAddr); + temp = (temp&0x3b)|(PageIdx<<6); + outportb(BaseAddr, temp); +} + + +irqreturn_t nic_8019_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + u8 RxPageBeg, RxPageEnd; + u8 RxNextPage; + u8 RxStatus; + u16 *data,temp; + u16 i, RxLength,RxLen; + + struct sk_buff *skb; + struct net_device *dev = (struct net_device *) dev_id; + struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv; + + TRACE("TX/RX Interupt!\n"); + spin_lock(&priv->lock); + SetRegPage(0); + outportb(BNRY, rBNRY); //??? + RxStatus = inportb(ISR); + if (RxStatus & 2) { + outportb(ISR, 0x2); //clr TX interupt + priv->stats.tx_packets++; + TRACE("transmit one packet complete!\n"); + } + + if (RxStatus & 1) { + TRACE("Receivex packet....\n"); + outportb(ISR, 0x1); //clr Rx interupt + SetRegPage(1); + RxPageEnd = inportb(CURR); + + SetRegPage(0); + RxPageBeg = rBNRY+1; + if(RxPageBeg>=RPSTOP) + RxPageBeg = RPSTART; + outportb(BaseAddr, 0x22); // stop remote dma + + //outport(RSAR0, RxPageBeg<<8); + //outport(RBCR0, 256); + outportb(RSAR0, 0); + outportb(RSAR1, RxPageBeg); + outportb(RBCR0, 4); + outportb(RBCR1, 0); + outportb(BaseAddr, 0xa); + +#ifdef RTL8019_OP_16 + temp = inportw(RWPORT); + RxNextPage = temp>>8; + RxStatus = temp&0xff; + RxLength = inportw(RWPORT); +#else + RxStatus = inportb(RWPORT); + RxNextPage = inportb(RWPORT); + RxLength = inportb(RWPORT); + RxLength |= inportb(RWPORT)<<8; +#endif + TRACE("\nRxBeg = %x, RxEnd = %x, nextpage = %x, size = %i\n", RxPageBeg, RxPageEnd, RxNextPage, RxLength); + RxLength -= 4; + if (RxLength>ETH_FRAME_LEN) { + if (RxPageEnd==RPSTART) + rBNRY = RPSTOP-1; + else + rBNRY = RxPageEnd-1; + + outportb(BNRY, rBNRY); + TRACE("RxLength more long than %x\n", ETH_FRAME_LEN); + return IRQ_HANDLED; + } + + skb = dev_alloc_skb(RxLength+2); + if (!skb) { + TRACE("Rtl8019as eth: low on mem - packet dropped\n"); + priv->stats.rx_dropped++; + return IRQ_HANDLED; + } + + skb->dev = dev; + skb_reserve(skb, 2); + skb_put(skb, RxLength); + data = ( u16 *)skb->data; + + // eth_copy_and_sum(skb, data, len, 0); + outportb(RSAR0, 4); + outportb(RSAR1, RxPageBeg); + outportb(RBCR0, RxLength); + outportb(RBCR1, RxLength>>8); + outportb(BaseAddr, 0xa); +#ifdef RTL8019_OP_16 + i = 2; + data -= 2; + RxLen=(RxLength+1)/2; +#else + i = 4; + data -= 4; + RxLen=RxLength; +#endif + for(; RxLen--;) { +#ifdef RTL8019_OP_16 + static const int cmp_val = 0x7f; +#else + static const int cmp_val = 0xff; +#endif + if (!(i & cmp_val)) { + outportb(BNRY, RxPageBeg); + RxPageBeg++; + if(RxPageBeg>=RPSTOP) + RxPageBeg = RPSTART; + } +#ifdef RTL8019_OP_16 + data[i++] = inportw(RWPORT); + TRACE("%2X,%2X,", data[i-1]&0xff,data[i-1]>>8); +#else + data[i++] = inportb(RWPORT); + TRACE("%2X,", data[i-1]); +#endif + } + + TRACE("\n"); + outportb(BNRY, RxPageBeg); + rBNRY = RxPageBeg; + + skb->protocol = eth_type_trans(skb, dev); + TRACE("\nprotocol=%x\n", skb->protocol); + priv->stats.rx_packets++; + priv->stats.rx_bytes +=RxLength; + netif_rx(skb); + } else { + outportb(ISR, 0xfe); + } + + spin_unlock(&priv->lock); + return IRQ_HANDLED; +} + + +/* + * Open and Close + */ +static int nic_8019_open(struct net_device *dev) +{ + int i,j; + + MOD_INC_USE_COUNT; + TRACE("open\n"); + // Disable irqs + disable_irq(dev->irq); + // register rx isr + if (request_irq(dev->irq, &nic_8019_rx, SA_INTERRUPT, "eth rx isr", dev)) { + printk(KERN_ERR "Rtl8019: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + // wake up Rtl8019as + SetRegPage(3); + outportb(CR9346, 0xcf); //set eem1-0, 11 ,enable write config register + outportb(CONFIG3, 0x60); //clear pwrdn, sleep mode, set led0 as led_col, led1 as led_crs + outportb(CR9346, 0x3f); //disable write config register + + // initialize + outportb(RstAddr, 0x5a); + i = 20000; + while(i--); + + + SetRegPage(0); + inportb(ISR); + outportb(BaseAddr, 0x21); /* set page 0 and stop */ + outportb(Pstart, RPSTART); /* set Pstart 0x4c */ + outportb(Pstop, RPSTOP); /* set Pstop 0x80 */ + outportb(BNRY, RPSTART); /* BNRY-> the last page has been read */ + outportb(TPSR, SPSTART); /* SPSTART page start register, 0x40 */ + outportb(RCR, 0xcc); /* set RCR 0xcc */ + outportb(TCR, 0xe0); /* set TCR 0xe0 */ + outportb(DCR, 0xc9); /* set DCR 0xc9, 16bit DMA */ + + outportb(IMR, 0x03); /* set IMR 0x03, enable tx rx int */ + outportb(ISR, 0xff); /* clear ISR */ + + SetRegPage(1); + for(i=0; i<6; i++) + outportb(BaseAddr+(1+i)*2, dev->dev_addr[i]); // set mac id + + outportb(CURR, RPSTART+1); + outportb(MAR0, 0x00); + outportb(MAR1, 0x41); + outportb(MAR2, 0x00); + outportb(MAR3, 0x80); + outportb(MAR4, 0x00); + outportb(MAR5, 0x00); + outportb(MAR6, 0x00); + outportb(MAR7, 0x00); + outportb(BaseAddr, 0x22); /* set page 0 and start */ + rBNRY = RPSTART; + enable_irq(dev->irq); + // Start the transmit queue + netif_start_queue(dev); + + return 0; +} + +static int nic_8019_stop(struct net_device *dev) +{ + TRACE("stop\n"); + SetRegPage(3); + outportb(CR9346, 0xcf); // set eem1-0, 11 ,enable write config register + outportb(CONFIG3, 0x66); // enter pwrdn, sleep mode, set led0 as led_col, led1 as led_crs + outportb(CR9346, 0x3f); // disable write config register + + free_irq(dev->irq, dev); + netif_stop_queue(dev); + MOD_DEC_USE_COUNT; + + return 0; +} + +static int nic_8019_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int i; + u16 len,TxLen; + u16 *data; + struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv; + + TRACE("start_xmit\n"); + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + TRACE("\nTx Length = %i,%x,%x\n", len, skb->data[12], skb->data[13]); + data =(u16*) skb->data; + + outportb(BaseAddr,0x22); //switch to page 0 and stop remote dma + if (inportb(BaseAddr)&4) // last remote dma not complete,return 1 echo busy(error),retransmit next + return 1; +#ifdef bug_fix_for_write + //read page 42,0,42,0 before write if you have problem +#endif + outportb(RSAR0, 0); + outportb(RSAR1, SPSTART); + outportb(RBCR0, len&0xff); + outportb(RBCR1, len>>8); + outportb(BaseAddr, 0x12); //begin remote write + dev->trans_start = jiffies; +#ifdef RTL8019_OP_16 + TxLen=(len+1)/2; +#else + TxLen=len; +#endif + for(i=0; i>8); +#else + outportb(RWPORT, data[i]); // copy data to nic ram + TRACE("%2X,",skb->data[i]); +#endif + } + + TRACE("\n"); + outportb(TPSR, SPSTART); // transmit begin page 0x40 + outportb(TBCR0, len&0xff); + outportb(TBCR1, len>>8); + outportb(BaseAddr, 0x1e); // begin to send packet + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *nic_8019_get_stats(struct net_device *dev) +{ + struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv; + TRACE("get_stats\n"); + return &priv->stats; +} + +/******************************************************************************/ +static int nic_8019_init(struct net_device *dev) +{ + int i; + TRACE("init\n"); + ether_setup(dev); // Assign some of the fields + + // set net_device methods + dev->open = nic_8019_open; + dev->stop = nic_8019_stop; + dev->get_stats = nic_8019_get_stats; + dev->hard_start_xmit = nic_8019_start_xmit; + + // set net_device data members + dev->watchdog_timeo = timeout; + dev->irq = 22; + dev->dma = 0; + + // set MAC address manually + printk(KERN_INFO "%s: ", dev->name); + for(i=0; i<6; i++) { + dev->dev_addr[i] = SrcMacID[i]; + printk("%2.2x%c", dev->dev_addr[i], (i==5) ? ' ' : ':'); + } + printk("\n"); + + SET_MODULE_OWNER(dev); + + dev->priv = kmalloc(sizeof(struct nic_8019_priv), GFP_KERNEL); + if(dev->priv == NULL) + return -ENOMEM; + + memset(dev->priv, 0, sizeof(struct nic_8019_priv)); + spin_lock_init(&((struct nic_8019_priv *) dev->priv)->lock); + return 0; +} + +static struct net_device nic_8019_netdevs = { + init: nic_8019_init, +}; + +/* + * Finally, the module stuff + */ +int __init nic_8019_init_module(void) +{ + int result; + TRACE("init_module\n"); + + //Print version information + printk(KERN_INFO "%s", version); + + //register_netdev will call nic_8019_init() + if((result = register_netdev(&nic_8019_netdevs))) + printk("Rtl8019as eth: Error %i registering device \"%s\"\n", result, nic_8019_netdevs.name); + + return result ? 0 : -ENODEV; +} + +void __exit nic_8019_cleanup(void) +{ + TRACE("cleanup\n"); + kfree(nic_8019_netdevs.priv); + unregister_netdev(&nic_8019_netdevs); + return; +} + +module_init(nic_8019_init_module); +module_exit(nic_8019_cleanup); + +MODULE_DESCRIPTION("Rtl8019as ethernet driver"); +MODULE_AUTHOR("antiscle "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-s3c44b0x/driver/rtl8019.h b/arch/arm/mach-s3c44b0x/driver/rtl8019.h new file mode 100644 index 00000000..2eb895b3 --- /dev/null +++ b/arch/arm/mach-s3c44b0x/driver/rtl8019.h @@ -0,0 +1,55 @@ + +#define SHIFT(x) (x<<1) + +#define BaseAddr 0x6000000 +#define RWPORT (BaseAddr+SHIFT(0x10)) /* dma read write address, form 0x10 - 0x17 */ +#define RstAddr (BaseAddr+SHIFT(0x18)) /* reset register, 0x18, 0x1a, 0x1c, 0x1e even address is recommanded */ + +/* page 0 */ +#define Pstart (BaseAddr+SHIFT(1)) /* page start */ +#define Pstop (BaseAddr+SHIFT(2)) /* page stop */ +#define BNRY (BaseAddr+SHIFT(3)) +#define TPSR (BaseAddr+SHIFT(4)) /* transmit page start */ +#define TBCR0 (BaseAddr+SHIFT(5)) +#define TBCR1 (BaseAddr+SHIFT(6)) +#define ISR (BaseAddr+SHIFT(7)) /* interrupt status register */ + +#define RSAR0 (BaseAddr+SHIFT(8)) /* dma read address */ +#define RSAR1 (BaseAddr+SHIFT(9)) +#define RBCR0 (BaseAddr+SHIFT(10)) /* dma read byte count */ +#define RBCR1 (BaseAddr+SHIFT(11)) + +#define RCR (BaseAddr+SHIFT(12)) /* receive config */ +#define TCR (BaseAddr+SHIFT(13)) /* transmit config */ +#define DCR (BaseAddr+SHIFT(14)) /* data config */ +#define IMR (BaseAddr+SHIFT(15)) /* interrupt mask */ + +#define ID8019L (BaseAddr+SHIFT(10)) +#define ID8019H (BaseAddr+SHIFT(11)) + +/* page 1 */ +#define PAR0 (BaseAddr+SHIFT(1)) +#define PAR1 (BaseAddr+SHIFT(2)) +#define PAR2 (BaseAddr+SHIFT(3)) +#define PAR3 (BaseAddr+SHIFT(4)) +#define PAR4 (BaseAddr+SHIFT(5)) +#define PAR6 (BaseAddr+SHIFT(6)) + +#define CURR (BaseAddr+SHIFT(7)) +#define MAR0 (BaseAddr+SHIFT(8)) +#define MAR1 (BaseAddr+SHIFT(9)) +#define MAR2 (BaseAddr+SHIFT(10)) +#define MAR3 (BaseAddr+SHIFT(11)) +#define MAR4 (BaseAddr+SHIFT(12)) +#define MAR5 (BaseAddr+SHIFT(13)) +#define MAR6 (BaseAddr+SHIFT(14)) +#define MAR7 (BaseAddr+SHIFT(15)) + +/* page 2 */ + +/* page 3 */ +#define CR9346 (BaseAddr+SHIFT(1)) +#define CONFIG0 (BaseAddr+SHIFT(3)) +#define CONFIG1 (BaseAddr+SHIFT(4)) +#define CONFIG2 (BaseAddr+SHIFT(5)) +#define CONFIG3 (BaseAddr+SHIFT(6)) diff --git a/arch/arm/mach-s3c44b0x/head.S b/arch/arm/mach-s3c44b0x/head.S new file mode 100644 index 00000000..a8118c2c --- /dev/null +++ b/arch/arm/mach-s3c44b0x/head.S @@ -0,0 +1,73 @@ +/* + * linux/arch/armnommu/mach-s3c44b0x/head.S + */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + /* + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + */ + mov r0, #PSR_I_BIT | MODE_SVC @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* handle CPU Cache */ + ldr r4, =S3C44B0X_SYSCFG + mov r5, #0x0e + str r5, [r4] + + /* Pretend we know what our processor code is (for arm_id) */ + + + ldr r2, S3C44B0_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, S3C44B0_MACH_TYPE + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + +S3C44B0_PROCESSOR_TYPE: + .long 0x44b07700 +S3C44B0_MACH_TYPE: + .long MACH_TYPE_S3C44B0 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-s3c44b0x/irq.c b/arch/arm/mach-s3c44b0x/irq.c new file mode 100644 index 00000000..3868c19c --- /dev/null +++ b/arch/arm/mach-s3c44b0x/irq.c @@ -0,0 +1,142 @@ +/* + * linux/arch/arm/mach-s3c44b0x/irq.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +void __inline__ s3c44b0x_mask_irq(unsigned int irq) +{ + SYSREG_OR_SET(S3C44B0X_INTMSK, 1< +#include +#include + +#include +#include +#include +#include + +#include + +static void __init s3c44b0x_map_io(void) +{ + return; +} diff --git a/arch/arm/mach-s3c44b0x/time.c b/arch/arm/mach-s3c44b0x/time.c new file mode 100644 index 00000000..df7501fd --- /dev/null +++ b/arch/arm/mach-s3c44b0x/time.c @@ -0,0 +1,104 @@ +/* + * for 2.6.8.1 port by + * Hyok S. Choi + * linux/arch/armnommu/mach-s3c44b0x/time.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S3C44B0X_SYSTIMER_DIVIDER 2 +extern int s3c44b0x_fMHZ; +extern int s3c44b0x_finMHZ; + +/* the system clock is in MHz unit, here I use the prescale value for 1 us resolution */ + +#if CONFIG_ARM_CLK_ADJUST +void s3c44b0x_systimer_setup(void) +#else +void __init s3c44b0x_systimer_setup(void) +#endif +{ + int prescale = s3c44b0x_fMHZ / S3C44B0X_SYSTIMER_DIVIDER; + int cnt = s3c44b0x_fMHZ * 1000000 / prescale / S3C44B0X_SYSTIMER_DIVIDER / HZ; + + SYSREG_CLR (S3C44B0X_TCON,0x7<<24); // stop timer 5 + SYSREG_SET (S3C44B0X_TCNTB5, cnt); + SYSREG_OR_SET (S3C44B0X_TCON, 2<<24); // update timer5 counter + + SYSREG_OR_SET (S3C44B0X_TCFG0, (prescale - 1) << 16); // set prescale, bit 16-23 + SYSREG_AND_SET (S3C44B0X_TCFG1, 0xff0fffff); // set timer5 divider, bit 20-23. 0 for 1/2 +} + +void __inline__ s3c44b0x_systimer_start(void) +{ + SYSREG_CLR (S3C44B0X_TCON, 0x02<<24); + SYSREG_OR_SET (S3C44B0X_TCON, 0x05<<24); +} + +/* + * Set up timer interrupt. + */ +#if CONFIG_ARM_CLK_ADJUST +void s3c44b0x_led_off(int); +void s3c44b0x_led_on(int); +#endif + +unsigned long s3c44b0x_gettimeoffset (void) +{ + return SYSREG_GETW(S3C44B0X_TCNTB5); +} + +static irqreturn_t s3c44b0x_timer_interrupt(int irq, void *dev_id) +{ +#if CONFIG_DEBUG_NICKMIT + static int cnt = 0; + ++cnt; + if (cnt == HZ) { + static int stat = 0; + cnt = 0; + if (stat) + s3c44b0x_led_on(0); + else + s3c44b0x_led_off(0); + stat = 1 - stat; + } +#endif + timer_tick(); + + return IRQ_HANDLED; +} + +static struct irqaction s3c44b0x_timer_irq = { + .name = "S3C44B0X Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = s3c44b0x_timer_interrupt +}; + + +void __init s3c44b0x_time_init(void) +{ + s3c44b0x_systimer_setup(); + /* + * @todo do those really need to be function pointers ? + */ + gettimeoffset = s3c44b0x_gettimeoffset; + s3c44b0x_timer_irq.handler = s3c44b0x_timer_interrupt; + + setup_irq(S3C44B0X_INTERRUPT_TIMER5, &s3c44b0x_timer_irq); + s3c44b0x_clear_pb(S3C44B0X_INTERRUPT_TIMER5); + s3c44b0x_unmask_irq(S3C44B0X_INTERRUPT_TIMER5); + + s3c44b0x_systimer_start(); +} + diff --git a/arch/arm/mach-s5c7375/Kconfig b/arch/arm/mach-s5c7375/Kconfig new file mode 100644 index 00000000..76e6090b --- /dev/null +++ b/arch/arm/mach-s5c7375/Kconfig @@ -0,0 +1,3 @@ +menu "S5C7375 Options" + depends on ARCH_S5C7375 +endmenu diff --git a/arch/arm/mach-s5c7375/Makefile b/arch/arm/mach-s5c7375/Makefile new file mode 100644 index 00000000..bc70c325 --- /dev/null +++ b/arch/arm/mach-s5c7375/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += arch.o irq.o dma.o time.o diff --git a/arch/arm/mach-s5c7375/Makefile.boot b/arch/arm/mach-s5c7375/Makefile.boot new file mode 100644 index 00000000..d02b226e --- /dev/null +++ b/arch/arm/mach-s5c7375/Makefile.boot @@ -0,0 +1,2 @@ + zreladdr-y := 0x00008000 +initrd_phys-y := 0x00300000 diff --git a/arch/arm/mach-s5c7375/arch.c b/arch/arm/mach-s5c7375/arch.c new file mode 100644 index 00000000..322481fe --- /dev/null +++ b/arch/arm/mach-s5c7375/arch.c @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-s5c7375/arch.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co.,Ltd. + * Hyok S. Choi (hyok.choi@samsung.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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void s5c7375_time_init(void); +extern unsigned long s5c7375_gettimeoffset(void); + +extern void __init s5c7375_init_irq(void); + +extern struct sys_timer s5c7375_timer; + +MACHINE_START(S5C7375, "S5C7375, SAMSUNG ELECTRONICS Co., Ltd.") + MAINTAINER("Hyok S. Choi ") + INITIRQ(s5c7375_init_irq) + .timer = &s5c7375_timer, +MACHINE_END diff --git a/arch/arm/mach-s5c7375/dma.c b/arch/arm/mach-s5c7375/dma.c new file mode 100644 index 00000000..b34e91f7 --- /dev/null +++ b/arch/arm/mach-s5c7375/dma.c @@ -0,0 +1,39 @@ +/* + * arch/arm/arch-s5c7375/dma-s5c7375.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS Co., Ltd. + * Hyok S. Choi (hyok.choi@samsung.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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void arch_dma_init(dma_t *dma) +{ +} diff --git a/arch/arm/mach-s5c7375/head.S b/arch/arm/mach-s5c7375/head.S new file mode 100644 index 00000000..417ff08a --- /dev/null +++ b/arch/arm/mach-s5c7375/head.S @@ -0,0 +1,162 @@ +/* + * linux/arch/armnommu/mach-s5c7375/head.S + * + * Copyright (C) 2003 Hyok S. Choi + * + * + * uClinux kernel startup code for s5c7375 + * which has no proper bootloader for linux startup + * because of XIP. + * + * 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 +#include + +#include +#include +#include +#include +#include + +#define MACHINFO_TYPE 0 +#define MACHINFO_PHYSRAM 4 +#define MACHINFO_PHYSIO 8 +#define MACHINFO_PGOFFIO 12 +#define MACHINFO_NAME 16 + + +/* + * Kernel startup entry point. + */ + __INIT + .type stext, #function +ENTRY(stext) + mov r12, r0 + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + +/* + * ARM920T need MMU enable for D-cache. + * we just make the identical table before the MMU enabling. + */ +#ifdef CONFIG_CPU_MXU_ENABLE + /* Write domain id (cp15_r3) */ + mvn r0, #0 /* Domains 0, 1 = client */ + mcr p15, 0, r0, c3, c0, 0 /* load domain access register */ + /* Set control register v4 */ + + mov r0, #0 + mcr p15, 0, r0, c13, c0, 0 /* zero PID */ + mcr p15, 0, r0, c7, c7, 0 /* invalidate I,D caches */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate I,D TLBs */ + mrc p15, 0, r0, c1, c0, 0 /* get control register */ + bic r0, r0, #0x0001 /* disable MMU */ + mcr p15, 0, r0, c1, c0, 0 /* write control register */ +init_ttb: + ldr r0,=0x00004000 @ set start of Translation Table base (16k Boundary) + mcr p15, 0, r0, c2, c0, 0 @ write to CP15 register 2 + /* + * + * Create translation table for flat mapping + * Top 12 bits of VA is pointer into table + * Create 4096 entries from 000xxxxx to fffxxxxx + * + */ + mov r1, #0x1000 + subs r1,r1,#1 + mov r2,#0b110000000000 @ set access permissions (AP) for full access SVC/USR (11:10) + orr r2,r2,#0b000111100000 @ set for domain 15 (8:5) + orr r2,r2,#0b000000010000 @ must be 1 (4) + orr r2,r2,#0b000000000000 @ set non cachable non bufferable (CB) (3:2) + orr r2,r2,#0b000000000010 @ set for 1Mb section (1:0) +init_ttb_1: + orr r3,r2,r1,lsl#20 @ use loop counter to create individual table entries + str r3,[r0,r1,lsl#2] @ str r3 at TTB base + loopcount*4 + subs r1,r1,#1 @ decrement loop counter + bpl init_ttb_1 + + /* resetting the SDRAM area to cacheable*/ + mov r1, #0x003 @ loop counter + + mov r2,#0b110000000000 @ set access permissions (AP) for full access SVC/USR (11:10) + orr r2,r2,#0b000111100000 @ set for domain 15 (8:5) + orr r2,r2,#0b000000010000 @ must be 1 (4) + orr r2,r2,#0b000000001100 @ set cachable but unbufferable (CB) (3:2) + orr r2,r2,#0b000000000010 @ set for 1Mb section (1:0) + +init_ttb_2: + orr r3,r2,r1,lsl#20 @ use loop counter to create individual table entries + str r3,[r0,r1,lsl#2] @ str r3 at TTB base + loopcount*4 + subs r1,r1,#1 @ decrement loop counter + bpl init_ttb_2 + @init_domains : we define all domains are manager. so no access permission check is occured. + mvn r0, #0 @ trick. 0 -1 == 0xFFFFFFFF + mcr p15, 0, r0, c3, c0, 0 @ write to CP15 register 5 +/* + * set global core configurations + */ + mrc p15, 0, r0, c1, c0, 0 @ read CP15 register 1 into r0 + + orr r0, r0, #(0x1 <<12) @ enable I Cache + orr r0, r0, #(0x1 <<2) @ enable D Cache + orr r0, r0, #(0b11 <<30) @ enable asynchronous clocking mode + orr r0, r0, #0x1 @ enable MMU + + mcr p15, 0, r0, c1, c0, 0 @ write cp15 register 1 + +#endif + +/* + * stuffs for cache are done. + * Now we setup the stack and machine id, and start the kernel! + */ + + adr r5, LC0 + ldmia r5, {r5, r6, r8, r9, sp} @ Setup stack + + /* Copy data sections to their new home. */ + + + /* Clear BSS */ + mov r4, #0 +1: cmp r5, r8 + strcc r4, [r5],#4 + bcc 1b + + /* Pretend we know what our processor code is (for arm_id) */ + + ldr r2, S5C7375_PROCESSOR_TYPE + + str r2, [r6] + ldr r2, S5C7375_MACH_TYPE + str r2, [r9] + + mov fp, #0 + b start_kernel + +LC0: .long __bss_start + .long processor_id + .long _end + .long __machine_arch_type + .long init_thread_union+8192 + +S5C7375_PROCESSOR_TYPE: + .long 0x41129200 +S5C7375_MACH_TYPE: + .long MACH_TYPE_S5C7375 + +#include "../kernel/head-common.S" diff --git a/arch/arm/mach-s5c7375/irq.c b/arch/arm/mach-s5c7375/irq.c new file mode 100644 index 00000000..a90d7ec3 --- /dev/null +++ b/arch/arm/mach-s5c7375/irq.c @@ -0,0 +1,147 @@ +/* + * linux/arch/armnommu/mach-s5c7375/irq.c + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +void __inline__ s5c7375_mask_irq(unsigned int irq) +{ + rINTMSK |= ((unsigned long) 1 << irq); +} + +void __inline__ s5c7375_unmask_irq(unsigned int irq) +{ + rINTMSK &= ~((unsigned long)1 << irq); +} + +void __inline__ s5c7375_mask_ack_irq(unsigned int irq) +{ + s5c7375_mask_irq(irq); +} + +void __inline__ s5c7375_clear_pb(unsigned int irq) +{ + rIRQISPC = (0x00000001< + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +unsigned long s5c7375_gettimeoffset (void) +{ + return (((RESCHED_PERIOD * CLOCKS_PER_USEC) /1000) - rT3LDR) / CLOCKS_PER_USEC; +} + +static irqreturn_t +s5c7375_timer_interrupt(int irq, void *dev_id) +{ + /* clear interrupt pending bit */ + rT3ISR = 0; + timer_tick(); + + return IRQ_HANDLED; +} + +static struct irqaction s5c7375_timer_irq = { + .name = "S5C7375 Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = s5c7375_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ + +void __init s5c7375_time_init (void) +{ + //- APB bus speed setting + /* + * Number of AHB clock cycles allocated in the ENABLE or + * SETUP state of the 2-nd APB peripheral minus one. + */ + rAPBCON2=(unsigned long)0x00010000; + + s5c7375_timer_irq.handler = s5c7375_timer_interrupt; + + /* + * Timer 3 is used for OS_timer by external clock. + */ + rT3CTR = TMR_TE_DISABLE | TMR_IE_PULSE | TMR_OE_ENABLE | TMR_UD_DOWN \ + | TMR_UDS_TxCTR | TMR_OM_PULSE | TMR_ES_POS | TMR_M_PERIODIC_TIMER; + + /* + * prescaler to 0x6B 'cause : + * 27M / (0x6B +1) = 4usec + */ + rT3PSR = SYS_TIMER03_PRESCALER; // 0x6B + /* rT3LDR = X second * (frequency/second ) */ + rT3LDR = RESCHED_PERIOD * CLOCKS_PER_USEC /1000; + /* is equal to + * RESCHED_PERIOD * 1000 // for msec to usec + * * (ECLK/ (SYS_TIMER03_PRESCALER +1)) /1000000; + * = 2500 + */ + /* clear interrupt pending bit */ + rT3ISR = 0; + + setup_irq(INT_N_TIMER3, &s5c7375_timer_irq); + + /* timer 3 enable it! */ + rT3CTR |= TMR_TE_ENABLE; + +} + + +struct sys_timer s5c7375_timer = { + .init = s5c7375_time_init, + .offset = s5c7375_gettimeoffset, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c0bfb821..4db4b294 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -58,6 +58,15 @@ config CPU_ARM710 Say Y if you want support for the ARM710 processor. Otherwise, say N. +# LPC22xx +config CPU_LPC22xx + bool "Support LPC22xx/ARM7TDMI processor" if !ARCH_LPC22xx + depends on ARCH_LPC22xx + default y if ARCH_LPC22xx + select CPU_32v4 + help + A Philips 32-bit RISC microprocessor based on ARM7TDMI-S core. + # ARM720T config CPU_ARM720T bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR @@ -131,15 +140,13 @@ config CPU_ARM920T # ARM922T config CPU_ARM922T bool "Support ARM922T processor" if ARCH_INTEGRATOR - depends on ARCH_LH7A40X || ARCH_INTEGRATOR - default y if ARCH_LH7A40X - select CPU_32v4T - select CPU_ABRT_EV4T - select CPU_CACHE_V4WT + depends on ARCH_LH7A40X || ARCH_INTEGRATOR || ARCH_KS8695 || ARCH_MOXART + default y if ARCH_LH7A40X || ARCH_KS8695 || ARCH_MOXART + select CPU_32v4 + select CPU_ABRT_NOMMU select CPU_CACHE_VIVT - select CPU_CP15_MMU - select CPU_COPY_V4WB if MMU - select CPU_TLB_V4WBI if MMU + select CPU_CP15 + select CPU_COPY_V4WB help The ARM922T is a version of the ARM920T, but with smaller instruction and data caches. It is used in Altera's @@ -518,12 +525,21 @@ config ARM_THUMB config CPU_BIG_ENDIAN bool "Build big-endian kernel" depends on ARCH_SUPPORTS_BIG_ENDIAN + default y if ARCH_S3C3410 help Say Y if you plan on running a kernel in big-endian mode. Note that your board must be properly built and your board port must properly enable any big-endian related features of your chipset/board/processor. +config CPU_MXU_ENABLE + depends !MMU + bool "Enable the MMU/MPU on non-paged memory management mode" + depends on CPU_ARM720T ||CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 + help + Say Y here to enable the memory control unit like: MMU/MPU, + on non-paged memory management mode. + config CPU_HIGH_VECTOR depends !MMU && CPU_CP15 && !CPU_ARM740T bool "Select the High exception vector" diff --git a/arch/arm/mm/Kconfig-bak-03032007 b/arch/arm/mm/Kconfig-bak-03032007 new file mode 100644 index 00000000..83a2c23c --- /dev/null +++ b/arch/arm/mm/Kconfig-bak-03032007 @@ -0,0 +1,627 @@ +comment "Processor Type" + +config CPU_32 + bool + default y + +# Select CPU types depending on the architecture selected. This selects +# which CPUs we support in the kernel image, and the compiler instruction +# optimiser behaviour. + +# ARM610 +config CPU_ARM610 + bool "Support ARM610 processor" + depends on ARCH_RPC + select CPU_32v3 + select CPU_CACHE_V3 + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V3 if MMU + select CPU_TLB_V3 if MMU + help + The ARM610 is the successor to the ARM3 processor + and was produced by VLSI Technology Inc. + + Say Y if you want support for the ARM610 processor. + Otherwise, say N. + +# ARM7TDMI +config CPU_ARM7TDMI + bool "Support ARM7TDMI processor" + depends on !MMU + select CPU_32v4T + select CPU_ABRT_LV4T + select CPU_CACHE_V4 + help + A 32-bit RISC microprocessor based on the ARM7 processor core + which has no memory control unit and cache. + + Say Y if you want support for the ARM7TDMI processor. + Otherwise, say N. + +# ARM710 +config CPU_ARM710 + bool "Support ARM710 processor" if !ARCH_CLPS7500 && ARCH_RPC + default y if ARCH_CLPS7500 + select CPU_32v3 + select CPU_CACHE_V3 + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V3 if MMU + select CPU_TLB_V3 if MMU + help + A 32-bit RISC microprocessor based on the ARM7 processor core + designed by Advanced RISC Machines Ltd. The ARM710 is the + successor to the ARM610 processor. It was released in + July 1994 by VLSI Technology Inc. + + Say Y if you want support for the ARM710 processor. + Otherwise, say N. + +# LPC22xx +config CPU_LPC22xx + bool "Support LPC22xx/ARM7TDMI processor" if !ARCH_LPC22xx + depends on ARCH_LPC22xx + default y if ARCH_LPC22xx + select CPU_32v4 + help + A Philips 32-bit RISC microprocessor based on ARM7TDMI-S core. + +# ARM720T +config CPU_ARM720T + bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR + default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 || ARCH_H720X + select CPU_32v4T + select CPU_ABRT_LV4T + select CPU_CACHE_V4 + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WT if MMU + select CPU_TLB_V4WT if MMU + help + A 32-bit RISC processor with 8kByte Cache, Write Buffer and + MMU built around an ARM7TDMI core. + + Say Y if you want support for the ARM720T processor. + Otherwise, say N. + +# ARM740T +config CPU_ARM740T + bool "Support ARM740T processor" if ARCH_INTEGRATOR + depends on !MMU + select CPU_32v4T + select CPU_ABRT_LV4T + select CPU_CACHE_V3 # although the core is v4t + select CPU_CP15_MPU + help + A 32-bit RISC processor with 8KB cache or 4KB variants, + write buffer and MPU(Protection Unit) built around + an ARM7TDMI core. + + Say Y if you want support for the ARM740T processor. + Otherwise, say N. + +# ARM9TDMI +config CPU_ARM9TDMI + bool "Support ARM9TDMI processor" + depends on !MMU + select CPU_32v4T + select CPU_ABRT_NOMMU + select CPU_CACHE_V4 + help + A 32-bit RISC microprocessor based on the ARM9 processor core + which has no memory control unit and cache. + + Say Y if you want support for the ARM9TDMI processor. + Otherwise, say N. + +# ARM920T +config CPU_ARM920T + bool "Support ARM920T processor" + depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 + default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200 + select CPU_32v4T + select CPU_ABRT_EV4T + select CPU_CACHE_V4WT + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WBI if MMU + help + The ARM920T is licensed to be produced by numerous vendors, + and is used in the Maverick EP9312 and the Samsung S3C2410. + + More information on the Maverick EP9312 at + . + + Say Y if you want support for the ARM920T processor. + Otherwise, say N. + +# ARM922T +config CPU_ARM922T + bool "Support ARM922T processor" if ARCH_INTEGRATOR + depends on ARCH_LH7A40X || ARCH_INTEGRATOR || ARCH_KS8695 || ARCH_MOXART + default y if ARCH_LH7A40X || ARCH_KS8695 || ARCH_MOXART + select CPU_32v4 + select CPU_ABRT_EV4 + select CPU_CACHE_VIVT + select CPU_CP15 + select CPU_COPY_V4WB if MMU + help + The ARM922T is a version of the ARM920T, but with smaller + instruction and data caches. It is used in Altera's + Excalibur XA device family. + + Say Y if you want support for the ARM922T processor. + Otherwise, say N. + +# ARM925T +config CPU_ARM925T + bool "Support ARM925T processor" if ARCH_OMAP1 + depends on ARCH_OMAP15XX + default y if ARCH_OMAP15XX + select CPU_32v4T + select CPU_ABRT_EV4T + select CPU_CACHE_V4WT + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WBI if MMU + help + The ARM925T is a mix between the ARM920T and ARM926T, but with + different instruction and data caches. It is used in TI's OMAP + device family. + + Say Y if you want support for the ARM925T processor. + Otherwise, say N. + +# ARM926T +config CPU_ARM926T + bool "Support ARM926T processor" + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 + default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 + select CPU_32v5 + select CPU_ABRT_EV5TJ + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WBI if MMU + help + This is a variant of the ARM920. It has slightly different + instruction sequences for cache and TLB operations. Curiously, + there is no documentation on it at the ARM corporate website. + + Say Y if you want support for the ARM926T processor. + Otherwise, say N. + +# ARM940T +config CPU_ARM940T + bool "Support ARM940T processor" if ARCH_INTEGRATOR + depends on !MMU + select CPU_32v4T + select CPU_ABRT_NOMMU + select CPU_CACHE_VIVT + select CPU_CP15_MPU + help + ARM940T is a member of the ARM9TDMI family of general- + purpose microprocessors with MPU and seperate 4KB + instruction and 4KB data cases, each with a 4-word line + length. + + Say Y if you want support for the ARM940T processor. + Otherwise, say N. + +# ARM946E-S +config CPU_ARM946E + bool "Support ARM946E-S processor" if ARCH_INTEGRATOR + depends on !MMU + select CPU_32v5 + select CPU_ABRT_NOMMU + select CPU_CACHE_VIVT + select CPU_CP15_MPU + help + ARM946E-S is a member of the ARM9E-S family of high- + performance, 32-bit system-on-chip processor solutions. + The TCM and ARMv5TE 32-bit instruction set is supported. + + Say Y if you want support for the ARM946E-S processor. + Otherwise, say N. + +# ARM1020 - needs validating +config CPU_ARM1020 + bool "Support ARM1020T (rev 0) processor" + depends on ARCH_INTEGRATOR + select CPU_32v5 + select CPU_ABRT_EV4T + select CPU_CACHE_V4WT + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WBI if MMU + help + The ARM1020 is the 32K cached version of the ARM10 processor, + with an addition of a floating-point unit. + + Say Y if you want support for the ARM1020 processor. + Otherwise, say N. + +# ARM1020E - needs validating +config CPU_ARM1020E + bool "Support ARM1020E processor" + depends on ARCH_INTEGRATOR + select CPU_32v5 + select CPU_ABRT_EV4T + select CPU_CACHE_V4WT + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WBI if MMU + depends on n + +# ARM1022E +config CPU_ARM1022 + bool "Support ARM1022E processor" + depends on ARCH_INTEGRATOR + select CPU_32v5 + select CPU_ABRT_EV4T + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU # can probably do better + select CPU_TLB_V4WBI if MMU + help + The ARM1022E is an implementation of the ARMv5TE architecture + based upon the ARM10 integer core with a 16KiB L1 Harvard cache, + embedded trace macrocell, and a floating-point unit. + + Say Y if you want support for the ARM1022E processor. + Otherwise, say N. + +# ARM1026EJ-S +config CPU_ARM1026 + bool "Support ARM1026EJ-S processor" + depends on ARCH_INTEGRATOR + select CPU_32v5 + select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU # can probably do better + select CPU_TLB_V4WBI if MMU + help + The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture + based upon the ARM10 integer core. + + Say Y if you want support for the ARM1026EJ-S processor. + Otherwise, say N. + +# SA110 +config CPU_SA110 + bool "Support StrongARM(R) SA-110 processor" if !ARCH_EBSA110 && !FOOTBRIDGE && !ARCH_TBOX && !ARCH_SHARK && !ARCH_NEXUSPCI && ARCH_RPC + default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_TBOX || ARCH_SHARK || ARCH_NEXUSPCI + select CPU_32v3 if ARCH_RPC + select CPU_32v4 if !ARCH_RPC + select CPU_ABRT_EV4 + select CPU_CACHE_V4WB + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_COPY_V4WB if MMU + select CPU_TLB_V4WB if MMU + help + The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and + is available at five speeds ranging from 100 MHz to 233 MHz. + More information is available at + . + + Say Y if you want support for the SA-110 processor. + Otherwise, say N. + +# SA1100 +config CPU_SA1100 + bool + depends on ARCH_SA1100 + default y + select CPU_32v4 + select CPU_ABRT_EV4 + select CPU_CACHE_V4WB + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_TLB_V4WB if MMU + +# XScale +config CPU_XSCALE + bool + depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000 + default y + select CPU_32v5 + select CPU_ABRT_EV5T + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_TLB_V4WBI if MMU + +# XScale Core Version 3 +config CPU_XSC3 + bool + depends on ARCH_IXP23XX + default y + select CPU_32v5 + select CPU_ABRT_EV5T + select CPU_CACHE_VIVT + select CPU_CP15_MMU + select CPU_TLB_V4WBI if MMU + select IO_36 + +# ARMv6 +config CPU_V6 + bool "Support ARM V6 processor" + depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 + select CPU_32v6 + select CPU_ABRT_EV6 + select CPU_CACHE_V6 + select CPU_CACHE_VIPT + select CPU_CP15_MMU + select CPU_COPY_V6 if MMU + select CPU_TLB_V6 if MMU + +# ARMv6k +config CPU_32v6K + bool "Support ARM V6K processor extensions" if !SMP + depends on CPU_V6 + default y if SMP + help + Say Y here if your ARMv6 processor supports the 'K' extension. + This enables the kernel to use some instructions not present + on previous processors, and as such a kernel build with this + enabled will not boot on processors with do not support these + instructions. + +# Figure out what processor architecture version we should be using. +# This defines the compiler instruction set which depends on the machine type. +config CPU_32v3 + bool + select TLS_REG_EMUL if SMP || !MMU + select NEEDS_SYSCALL_FOR_CMPXCHG if SMP + +config CPU_32v4 + bool + select TLS_REG_EMUL if SMP || !MMU + select NEEDS_SYSCALL_FOR_CMPXCHG if SMP + +config CPU_32v4T + bool + select TLS_REG_EMUL if SMP || !MMU + select NEEDS_SYSCALL_FOR_CMPXCHG if SMP + +config CPU_32v5 + bool + select TLS_REG_EMUL if SMP || !MMU + select NEEDS_SYSCALL_FOR_CMPXCHG if SMP + +config CPU_32v6 + bool + +# The abort model +config CPU_ABRT_NOMMU + bool + +config CPU_ABRT_EV4 + bool + +config CPU_ABRT_EV4T + bool + +config CPU_ABRT_LV4T + bool + +config CPU_ABRT_EV5T + bool + +config CPU_ABRT_EV5TJ + bool + +config CPU_ABRT_EV6 + bool + +# The cache model +config CPU_CACHE_V3 + bool + +config CPU_CACHE_V4 + bool + +config CPU_CACHE_V4WT + bool + +config CPU_CACHE_V4WB + bool + +config CPU_CACHE_V6 + bool + +config CPU_CACHE_VIVT + bool + +config CPU_CACHE_VIPT + bool + +if MMU +# The copy-page model +config CPU_COPY_V3 + bool + +config CPU_COPY_V4WT + bool + +config CPU_COPY_V4WB + bool + +config CPU_COPY_V6 + bool + +# This selects the TLB model +config CPU_TLB_V3 + bool + help + ARM Architecture Version 3 TLB. + +config CPU_TLB_V4WT + bool + help + ARM Architecture Version 4 TLB with writethrough cache. + +config CPU_TLB_V4WB + bool + help + ARM Architecture Version 4 TLB with writeback cache. + +config CPU_TLB_V4WBI + bool + help + ARM Architecture Version 4 TLB with writeback cache and invalidate + instruction cache entry. + +config CPU_TLB_V6 + bool + +endif + +config CPU_CP15 + bool + help + Processor has the CP15 register. + +config CPU_CP15_MMU + bool + select CPU_CP15 + help + Processor has the CP15 register, which has MMU related registers. + +config CPU_CP15_MPU + bool + select CPU_CP15 + help + Processor has the CP15 register, which has MPU related registers. + +# +# CPU supports 36-bit I/O +# +config IO_36 + bool + +comment "Processor Features" + +config ARM_THUMB + bool "Support Thumb user binaries" + depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 + default y + help + Say Y if you want to include kernel support for running user space + Thumb binaries. + + The Thumb instruction set is a compressed form of the standard ARM + instruction set resulting in smaller binaries at the expense of + slightly less efficient code. + + If you don't know what this all is, saying Y is a safe choice. + +config CPU_BIG_ENDIAN + bool "Build big-endian kernel" + depends on ARCH_SUPPORTS_BIG_ENDIAN + default y if ARCH_S3C3410 + help + Say Y if you plan on running a kernel in big-endian mode. + Note that your board must be properly built and your board + port must properly enable any big-endian related features + of your chipset/board/processor. + +config CPU_MXU_ENABLE + depends !MMU + bool "Enable the MMU/MPU on non-paged memory management mode" + depends on CPU_ARM720T ||CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 + help + Say Y here to enable the memory control unit like: MMU/MPU, + on non-paged memory management mode. + +config CPU_HIGH_VECTOR + depends !MMU && CPU_CP15 && !CPU_ARM740T + bool "Select the High exception vector" + default n + help + Say Y here to select high exception vector(0xFFFF0000~). + The exception vector can be vary depending on the platform + design in nommu mode. If your platform needs to select + high exception vector, say Y. + Otherwise or if you are unsure, say N, and the low exception + vector (0x00000000~) will be used. + +config CPU_ICACHE_DISABLE + bool "Disable I-Cache (I-bit)" + depends on CPU_CP15 && !(CPU_ARM610 || CPU_ARM710 || CPU_ARM720T || CPU_ARM740T || CPU_XSCALE || CPU_XSC3) + help + Say Y here to disable the processor instruction cache. Unless + you have a reason not to or are unsure, say N. + +config CPU_DCACHE_DISABLE + bool "Disable D-Cache (C-bit)" + depends on CPU_CP15 + help + Say Y here to disable the processor data cache. Unless + you have a reason not to or are unsure, say N. + +config CPU_DCACHE_SIZE + hex + depends on CPU_ARM740T || CPU_ARM946E + default 0x00001000 if CPU_ARM740T + default 0x00002000 # default size for ARM946E-S + help + Some cores are synthesizable to have various sized cache. For + ARM946E-S case, it can vary from 0KB to 1MB. + To support such cache operations, it is efficient to know the size + before compile time. + If your SoC is configured to have a different size, define the value + here with proper conditions. + +config CPU_DCACHE_WRITETHROUGH + bool "Force write through D-cache" + depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE + default y if CPU_ARM925T + help + Say Y here to use the data cache in writethrough mode. Unless you + specifically require this or are unsure, say N. + +config CPU_CACHE_ROUND_ROBIN + bool "Round robin I and D cache replacement algorithm" + depends on (CPU_ARM926T || CPU_ARM946E || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE) + help + Say Y here to use the predictable round-robin cache replacement + policy. Unless you specifically require this or are unsure, say N. + +config CPU_BPREDICT_DISABLE + bool "Disable branch prediction" + depends on CPU_ARM1020 || CPU_V6 + help + Say Y here to disable branch prediction. If unsure, say N. + +config TLS_REG_EMUL + bool + help + An SMP system using a pre-ARMv6 processor (there are apparently + a few prototypes like that in existence) and therefore access to + that required register must be emulated. + +config HAS_TLS_REG + bool + depends on !TLS_REG_EMUL + default y if SMP || CPU_32v7 + help + This selects support for the CP15 thread register. + It is defined to be available on some ARMv6 processors (including + all SMP capable ARMv6's) or later processors. User space may + assume directly accessing that register and always obtain the + expected value only on ARMv7 and above. + +config NEEDS_SYSCALL_FOR_CMPXCHG + bool + help + SMP on a pre-ARMv6 processor? Well OK then. + Forget about fast user space cmpxchg support. + It is just not possible. + diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index d2f5672e..b0f98279 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -2,14 +2,13 @@ # Makefile for the linux arm-specific parts of the memory manager. # -obj-y := consistent.o extable.o fault.o init.o \ - iomap.o +obj-y := extable.o fault.o init.o iomap.o obj-$(CONFIG_MMU) += fault-armv.o flush.o ioremap.o mmap.o \ - pgd.o mmu.o + pgd.o mmu.o consistent.o ifneq ($(CONFIG_MMU),y) -obj-y += nommu.o +obj-y += nommu.o consistent-nommu.o endif obj-$(CONFIG_MODULES) += proc-syms.o @@ -45,6 +44,8 @@ obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o +obj-$(CONFIG_CPU_S3C4510B) += proc-s3c4510b.o +obj-$(CONFIG_CPU_LPC22xx) += proc-lpc22xx.o obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM7TDMI) += proc-arm7tdmi.o diff --git a/arch/arm/mm/abort-ev0.S b/arch/arm/mm/abort-ev0.S new file mode 100644 index 00000000..4aeb1e0c --- /dev/null +++ b/arch/arm/mm/abort-ev0.S @@ -0,0 +1,37 @@ +/* + * linux/arch/arm/mm/abort-ev0t.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 +#include +/* + * Function: v0_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(v0_early_abort) + ldr r3, [r2] @ read aborted ARM instruction + bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR + tst r3, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 11 @ yes. + mov pc, lr + + diff --git a/arch/arm/mm/abort-ev0t.S b/arch/arm/mm/abort-ev0t.S new file mode 100644 index 00000000..b3b173bd --- /dev/null +++ b/arch/arm/mm/abort-ev0t.S @@ -0,0 +1,38 @@ +/* + * linux/arch/arm/mm/abort-ev0t.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 +#include +/* + * Function: v0t_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 11 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(v0t_early_abort) + tst r3, #PSR_T_BIT + ldrneh r3, [r2] @ read aborted thumb instruction + ldreq r3, [r2] @ read aborted ARM instruction + bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR + movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 + tst r3, #1 << 20 @ check write + orreq r1, r1, #1 << 11 + mov pc, lr diff --git a/arch/arm/mm/cache-v0.S b/arch/arm/mm/cache-v0.S new file mode 100644 index 00000000..a833ee0d --- /dev/null +++ b/arch/arm/mm/cache-v0.S @@ -0,0 +1,132 @@ +/* + * linux/arch/arm/mm/cache-v0.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 +#include +#include +#include +#include "proc-macros.S" + +/* + * flush_user_cache_all() + * + * Invalidate all cache entries in a particular address + * space. + * + * - mm - mm_struct describing address space + */ +ENTRY(v0_flush_user_cache_all) + /* FALLTHROUGH */ +/* + * flush_kern_cache_all() + * + * Clean and invalidate the entire cache. + */ +ENTRY(v0_flush_kern_cache_all) + /* FALLTHROUGH */ + +/* + * flush_user_cache_range(start, end, flags) + * + * Invalidate a range of cache entries in the specified + * address space. + * + * - start - start address (may not be aligned) + * - end - end address (exclusive, may not be aligned) + * - flags - vma_area_struct flags describing address space + */ +ENTRY(v0_flush_user_cache_range) + /* FALLTHROUGH */ + +/* + * coherent_kern_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v0_coherent_kern_range) + /* FALLTHROUGH */ + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v0_coherent_user_range) + /* FALLTHROUGH */ + +/* + * flush_kern_dcache_page(void *page) + * + * Ensure no D cache aliasing occurs, either with itself or + * the I cache + * + * - addr - page aligned address + */ +ENTRY(v0_flush_kern_dcache_page) + /* FALLTHROUGH */ + +/* + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v0_dma_inv_range) + /* FALLTHROUGH */ + +/* + * dma_flush_range(start, end) + * + * Clean and invalidate the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v0_dma_flush_range) + /* FALLTHROUGH */ + +/* + * dma_clean_range(start, end) + * + * Clean (write back) the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(v0_dma_clean_range) + mov pc, lr + + __INITDATA + + .type v0_cache_fns, #object +ENTRY(v0_cache_fns) + .long v0_flush_kern_cache_all + .long v0_flush_user_cache_all + .long v0_flush_user_cache_range + .long v0_coherent_kern_range + .long v0_flush_kern_dcache_page + .long v0_dma_inv_range + .long v0_dma_clean_range + .long v0_dma_flush_range + .size v0_cache_fns, . - v0_cache_fns diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index e1994788..1981ce73 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -42,9 +42,13 @@ ENTRY(v3_flush_kern_cache_all) * - flags - vma_area_struct flags describing address space */ ENTRY(v3_flush_user_cache_range) +#ifdef CONFIG_CPU_CP15 mov ip, #0 mcreq p15, 0, ip, c7, c0, 0 @ flush ID cache mov pc, lr +#else + /* FALLTHROUGH */ +#endif /* * coherent_kern_range(start, end) @@ -106,8 +110,10 @@ ENTRY(v3_dma_inv_range) * - end - virtual end address */ ENTRY(v3_dma_flush_range) +#ifdef CONFIG_CPU_CP15 mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ flush ID cache +#endif /* FALLTHROUGH */ /* diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index b2908063..652ff6c7 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -29,7 +29,7 @@ ENTRY(v4_flush_user_cache_all) * Clean and invalidate the entire cache. */ ENTRY(v4_flush_kern_cache_all) -#ifdef CPU_CP15 +#ifdef CONFIG_CPU_CP15 mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ flush ID cache mov pc, lr @@ -48,7 +48,7 @@ ENTRY(v4_flush_kern_cache_all) * - flags - vma_area_struct flags describing address space */ ENTRY(v4_flush_user_cache_range) -#ifdef CPU_CP15 +#ifdef CONFIG_CPU_CP15 mov ip, #0 mcreq p15, 0, ip, c7, c7, 0 @ flush ID cache mov pc, lr @@ -116,7 +116,7 @@ ENTRY(v4_dma_inv_range) * - end - virtual end address */ ENTRY(v4_dma_flush_range) -#ifdef CPU_CP15 +#ifdef CONFIG_CPU_CP15 mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ flush ID cache #endif diff --git a/arch/arm/mm/consistent-nommu.c b/arch/arm/mm/consistent-nommu.c new file mode 100644 index 00000000..8e2d5c80 --- /dev/null +++ b/arch/arm/mm/consistent-nommu.c @@ -0,0 +1,212 @@ +/* + * arch/arm/mm/consistent-nommu.c + * Based on arch/arm/mm/consistent.c + * + * Copyright (C) 2000-2004 Russell King + * Modified by Catalin Marinas for noMMU support + * + * 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. + * + * DMA uncached mapping support. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* set_page_count */ +#include "../../../mm/internal.h" + +static void * +__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, + pgprot_t prot) +{ + struct page *page; + void *page_addr; + unsigned long order; + u64 mask = ISA_DMA_THRESHOLD, limit; + + if (dev) { + mask = dev->coherent_dma_mask; + + /* + * Sanity check the DMA mask - it must be non-zero, and + * must be able to be satisfied by a DMA allocation. + */ + if (mask == 0) { + dev_warn(dev, "coherent DMA mask is unset\n"); + goto no_page; + } + + if ((~mask) & ISA_DMA_THRESHOLD) { + dev_warn(dev, "coherent DMA mask %#llx is smaller " + "than system GFP_DMA mask %#llx\n", + mask, (unsigned long long)ISA_DMA_THRESHOLD); + goto no_page; + } + } + + /* + * Sanity check the allocation size. + */ + size = PAGE_ALIGN(size); + limit = (mask + 1) & ~mask; + if (limit && size >= limit) { + printk(KERN_WARNING "coherent allocation too big " + "(requested %#x mask %#llx)\n", size, mask); + goto no_page; + } + + order = get_order(size); + + if (mask != 0xffffffff) + gfp |= GFP_DMA; + + page = alloc_pages(gfp, order); + if (!page) + goto no_page; + + /* + * Invalidate any data that might be lurking in the + * kernel direct-mapped region for device DMA. + */ + { + unsigned long kaddr = (unsigned long)page_address(page); + memset(page_address(page), 0, size); + dmac_flush_range(kaddr, kaddr + size); + } + + /* + * Set the "dma handle" + */ + *handle = page_to_dma(dev, page); + page_addr = page_address(page); + + do { + set_page_count(page, 1); + /* + * x86 does not mark the pages reserved... + */ + SetPageReserved(page); + page++; + } while (size -= PAGE_SIZE); + + return page_addr; + + no_page: + *handle = ~0; + return NULL; +} + +/* + * Allocate DMA-coherent memory space and return both the kernel remapped + * virtual and bus address for that space. + */ +void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +{ + return __dma_alloc(dev, size, handle, gfp, + pgprot_noncached(pgprot_kernel)); +} +EXPORT_SYMBOL(dma_alloc_coherent); + +/* + * Allocate a writecombining region, in much the same way as + * dma_alloc_coherent above. + */ +void * +dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +{ + return __dma_alloc(dev, size, handle, gfp, + pgprot_writecombine(pgprot_kernel)); +} +EXPORT_SYMBOL(dma_alloc_writecombine); + +static int dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + unsigned long user_size; + int ret = -ENXIO; + + user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + vma->vm_flags |= VM_RESERVED; + + /* Equivalent to: vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; */ + ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + user_size << PAGE_SHIFT, vma->vm_page_prot); + + return ret; +} + +int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_coherent); + +int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_writecombine); + +/* + * free a page as defined by the above mapping. + */ +void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle) +{ + struct page *page; + + size = PAGE_ALIGN(size); + + page = virt_to_page(cpu_addr); + do { + + /* + * x86 does not mark the pages reserved... + */ + ClearPageReserved(page); + + __free_page(page); + page++; + } while (size -= PAGE_SIZE); +} +EXPORT_SYMBOL(dma_free_coherent); + +/* + * Make an area consistent for devices. + */ +void consistent_sync(void *vaddr, size_t size, int direction) +{ + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + + switch (direction) { + case DMA_FROM_DEVICE: /* invalidate only */ + dmac_inv_range(start, end); + break; + case DMA_TO_DEVICE: /* writeback only */ + dmac_clean_range(start, end); + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + dmac_flush_range(start, end); + break; + default: + BUG(); + } +} +EXPORT_SYMBOL(consistent_sync); diff --git a/arch/arm/mm/copypage-v4wb.S b/arch/arm/mm/copypage-v4wb.S index 83117354..d0343e05 100644 --- a/arch/arm/mm/copypage-v4wb.S +++ b/arch/arm/mm/copypage-v4wb.S @@ -28,6 +28,7 @@ * own copy_user_page that does the right thing. */ ENTRY(v4wb_copy_user_page) +#if 0 /* mask by Victor Yu. 06-09-2005 */ stmfd sp!, {r4, lr} @ 2 mov r2, #PAGE_SZ/64 @ 1 ldmia r1!, {r3, r4, ip, lr} @ 4 @@ -45,6 +46,39 @@ ENTRY(v4wb_copy_user_page) bne 1b @ 1 mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB ldmfd sp!, {r4, pc} @ 3 +#else /* add by Victor Yu. 06-09-2005 */ +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + /* Write through */ + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/32 @ 1 + + ldmia r1!, {r3, r4, ip, lr} @ 4 +1: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + + mcr p15, 0, r2, c7, c7, 0 @ flush ID cache + ldmfd sp!, {r4, pc} @ 3 +#else + /* Write back */ + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/32 @ 1 + +1: ldmia r1!, {r3, r4, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + bne 1b + mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB + ldmfd sp!, {r4, pc} @ 3 +#endif /* CONFIG_CPU_DCACHE_WRITETHROUGH */ +#endif .align 5 /* @@ -53,6 +87,7 @@ ENTRY(v4wb_copy_user_page) * Same story as above. */ ENTRY(v4wb_clear_user_page) +#if 0 /* mask by Victor Yu. 06-09-2005 */ str lr, [sp, #-4]! mov r1, #PAGE_SZ/64 @ 1 mov r2, #0 @ 1 @@ -69,6 +104,34 @@ ENTRY(v4wb_clear_user_page) bne 1b @ 1 mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB ldr pc, [sp], #4 +#else /* add by Victor Yu. 06-09-2005 */ + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/32 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + /* Write through */ +1: stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + + mcr p15, 0, r1, c7, c7, 0 @ flush ID cache + ldr pc, [sp], #4 +#else + /* Write back */ +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB + ldr pc, [sp], #4 +#endif /* CONFIG_CPU_DCACHE_WRITETHROUGH */ +#endif __INITDATA diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 5e658a87..6f04ad66 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -3,6 +3,7 @@ * * Copyright (C) 1995 Linus Torvalds * Modifications for ARM processor (c) 1995-2004 Russell King + * Modifications for nommu or non-paged, Hyok S. Choi, 2003 * * 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 @@ -21,6 +22,15 @@ #include "fault.h" +struct fsr_info { + int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); + int sig; + int code; + const char *name; +}; +static struct fsr_info fsr_info[]; + +#ifdef CONFIG_MMU /* * This is useful to dump out the page tables associated with * 'addr' in mm 'mm'. @@ -367,6 +377,112 @@ do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) } /* + * Dispatch a data abort to the relevant handler. + */ +asmlinkage void +do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); + struct siginfo info; + + if (!inf->fn(addr, fsr, regs)) + return; + + printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", + inf->name, fsr, addr); + + info.si_signo = inf->sig; + info.si_errno = 0; + info.si_code = inf->code; + info.si_addr = (void __user *)addr; + notify_die("", regs, &info, fsr, 0); +} + +asmlinkage void +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) +{ + do_translation_fault(addr, 0, regs); +} + +#else /* !CONFIG_MMU */ + +/* + * In nommu mode, all the handler always returns "fault". + */ +static int +do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + return 1; +} + +static int +do_translation_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + return 1; +} + +static int +do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + return 1; +} + +/* + * Dispatch a data abort to the relevant handler. + */ +asmlinkage void +do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); + + if (!inf->fn(addr, fsr, regs)) + return; + + bust_spinlocks(1); + printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", + inf->name, fsr, addr); + die("Oops", regs, fsr); + bust_spinlocks(0); + do_exit(SIGKILL); +} + +asmlinkage void +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) +{ + bust_spinlocks(1); + printk(KERN_ALERT + "Unable to handle %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "abort", addr); + die("Oops", regs, -1); + bust_spinlocks(0); + do_exit(SIGKILL); +} + +void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + /* + * Are we prepared to handle this kernel fault? + */ + if (fixup_exception(regs)) + return; + + /* + * No handler, we'll have to terminate things with extreme prejudice. + */ + bust_spinlocks(1); + printk(KERN_ALERT + "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); + + die("Oops", regs, fsr); + bust_spinlocks(0); + do_exit(SIGKILL); +} +#endif /* !CONFIG_MMU */ + +/* * This abort handler always returns "fault". */ static int @@ -375,12 +491,7 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) return 1; } -static struct fsr_info { - int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); - int sig; - int code; - const char *name; -} fsr_info[] = { +static struct fsr_info fsr_info[] = { /* * The following are the standard ARMv3 and ARMv4 aborts. ARMv5 * defines these to be "precise" aborts. @@ -434,32 +545,3 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *) fsr_info[nr].name = name; } } - -/* - * Dispatch a data abort to the relevant handler. - */ -asmlinkage void -do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); - struct siginfo info; - - if (!inf->fn(addr, fsr, regs)) - return; - - printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", - inf->name, fsr, addr); - - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - notify_die("", regs, &info, fsr, 0); -} - -asmlinkage void -do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) -{ - do_translation_fault(addr, 0, regs); -} - diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 454205b7..4d61067f 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -13,6 +13,9 @@ #include #include + +#ifdef CONFIG_MMU + #include #include "mm.h" @@ -116,6 +119,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, #else #define flush_pfn_alias(pfn,vaddr) do { } while (0) #endif +#else +#define flush_pfn_alias(pfn,vaddr) do { } while (0) +#endif /* CONFIG_MMU */ void __flush_dcache_page(struct address_space *mapping, struct page *page) { diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index d0e66424..3055e9d7 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -76,7 +76,29 @@ void __iomem *__ioremap(unsigned long phys_addr, size_t size, } EXPORT_SYMBOL(__ioremap); -void __iounmap(void __iomem *addr) +void __iounmap(volatile void __iomem *addr) { } EXPORT_SYMBOL(__iounmap); + +/* + * You really shouldn't be using read() or write() on /dev/mem. This + * might go away in the future. + */ +int valid_phys_addr_range(unsigned long addr, size_t size) +{ + if (addr + size > __pa(high_memory)) + return 0; + + return 1; +} + +/* + * We don't use supersection mappings for mmap() on /dev/mem, which + * means that we can't map the memory area above the 4G barrier into + * userspace. + */ +int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) +{ + return !(pfn + (size >> PAGE_SHIFT) > 0x00100000); +} diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index c2f0705b..a2b4a1ae 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -162,7 +162,11 @@ __arm710_setup: arm710_cr1_clear: .word 0x0f3f arm710_cr1_set: +#if defined(CONFIG_MMU) || defined(CONFIG_CPU_MXU_ENABLE) .word 0x013d +#else + .word 0x013c +#endif .type __arm720_setup, #function __arm720_setup: diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S index 40713818..bdd1ec71 100644 --- a/arch/arm/mm/proc-arm740.S +++ b/arch/arm/mm/proc-arm740.S @@ -1,35 +1,192 @@ /* - * linux/arch/arm/mm/arm740.S: utility functions for ARM740 - * - * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@samsung.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. - * + * linux/arch/armnommu/mm/arm740.S: MPU functions for ARM740 + * + * Copyright (C) 1997-2000 Russell King + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * Rob Scott (rscott@mtrob.fdns.net) + * Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd. + * Copyright (C) 2004 Hyok S. Choi (hyok.choi@samsung.com) */ + #include -#include +#include #include -#include -#include -#include +#include #include +#include +#include #include +#include "proc-macros.S" + - .text /* - * cpu_arm740_proc_init() - * cpu_arm740_do_idle() - * cpu_arm740_dcache_clean_area() - * cpu_arm740_switch_mm() + * cpu_arm740_data_abort() + * + * obtain information about current aborted instruction * - * These are not required. + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +Ldata_ldmstm: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r2, r4, r7, lsl #1 + add r0, r0, r2, lsr #1 + and r2, r4, r7, lsl #2 + add r0, r0, r2, lsr #2 + and r2, r4, r7, lsl #3 + add r0, r0, r2, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] @ Get register + tst r4, #1 << 23 @ U bit + subne r7, r0, r7, lsl #2 + addeq r7, r0, r7, lsl #2 @ Do correction (signed) +Ldata_saver7: + str r7, [sp, r5, lsr #14] @ Put register +Ldata_simple: + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #255 + mov pc, lr + +ENTRY(cpu_arm740_data_abort) + ldr r4, [r0] @ read instruction causing problem + tst r4, r4, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 + and r2, r4, #15 << 24 + add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine + movs pc, lr + + b Ldata_lateldrhpost @ ldrh rd, [rn], #m/rm + b Ldata_lateldrhpre @ ldrh rd, [rn, #m/rm] + b Ldata_unknown + b Ldata_unknown + b Ldata_lateldrpostconst @ ldr rd, [rn], #m + b Ldata_lateldrpreconst @ ldr rd, [rn, #m] + b Ldata_lateldrpostreg @ ldr rd, [rn], rm + b Ldata_lateldrprereg @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, + b Ldata_ldmstm @ ldm*b rn, + b Ldata_unknown + b Ldata_unknown + b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_simple @ ldc rd, [rn, #m] + b Ldata_unknown + +Ldata_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r4 + mov r2, r3 + bl baddataabort + b ret_from_exception + +Ldata_lateldrhpre: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrhpost: + and r5, r4, #0x00f @ get Rm / low nibble of immediate value + tst r4, #1 << 22 @ if (immediate offset) + andne r2, r4, #0xf00 @ { immediate high nibble + orrne r2, r5, r2, lsr #4 @ combine nibbles } else + ldreq r2, [sp, r5, lsl #2] @ { load Rm value } + and r5, r4, #15 << 16 @ get Rn + ldr r0, [sp, r5, lsr #14] @ load Rn value + tst r4, #1 << 23 @ U bit + subne r7, r0, r2 + addeq r7, r0, r2 + b Ldata_saver7 + +Ldata_lateldrpreconst: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrpostconst: + movs r2, r4, lsl #20 @ Get offset + beq Ldata_simple + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r7, r0, r2, lsr #20 + addeq r7, r0, r2, lsr #20 + b Ldata_saver7 + +Ldata_lateldrprereg: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrpostreg: + and r5, r4, #15 + ldr r2, [sp, r5, lsl #2] @ Get Rm + mov r3, r4, lsr #7 + ands r3, r3, #31 + and r6, r4, #0x70 + orreq r6, r6, #8 + add pc, pc, r6 + mov r0, r0 + + mov r2, r2, lsl r3 @ 0: LSL #!0 + b 1f + b 1f @ 1: LSL #0 + mov r0, r0 + b 1f @ 2: MUL? + mov r0, r0 + b 1f @ 3: MUL? + mov r0, r0 + mov r2, r2, lsr r3 @ 4: LSR #!0 + b 1f + mov r2, r2, lsr #32 @ 5: LSR #32 + b 1f + b 1f @ 6: MUL? + mov r0, r0 + b 1f @ 7: MUL? + mov r0, r0 + mov r2, r2, asr r3 @ 8: ASR #!0 + b 1f + mov r2, r2, asr #32 @ 9: ASR #32 + b 1f + b 1f @ A: MUL? + mov r0, r0 + b 1f @ B: MUL? + mov r0, r0 + mov r2, r2, ror r3 @ C: ROR #!0 + b 1f + mov r2, r2, rrx @ D: RRX + b 1f + mov r0, r0 @ E: MUL? + mov r0, r0 + mov r0, r0 @ F: MUL? + + +1: and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r7, r0, r2 + addeq r7, r0, r2 + b Ldata_saver7 + + +/* + * cpu_arm740_check_bugs() + */ +ENTRY(cpu_arm740_check_bugs) + mrs ip, cpsr + bic ip, ip, #PSR_F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm740_proc_init() */ ENTRY(cpu_arm740_proc_init) -ENTRY(cpu_arm740_do_idle) -ENTRY(cpu_arm740_dcache_clean_area) -ENTRY(cpu_arm740_switch_mm) mov pc, lr /* @@ -40,10 +197,10 @@ ENTRY(cpu_arm740_proc_fin) mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip mrc p15, 0, r0, c1, c0, 0 - bic r0, r0, #0x3f000000 @ bank/f/lock/s - bic r0, r0, #0x0000000c @ w-buffer/cache + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. mcr p15, 0, r0, c1, c0, 0 @ disable caches - mcr p15, 0, r0, c7, c0, 0 @ invalidate cache + mcr p15, 0, r1, c7, c7, 0 @ invalidate cache ldmfd sp!, {pc} /* @@ -53,69 +210,73 @@ ENTRY(cpu_arm740_proc_fin) */ ENTRY(cpu_arm740_reset) mov ip, #0 - mcr p15, 0, ip, c7, c0, 0 @ invalidate cache + mcr p15, 0, ip, c7, c7, 0 @ invalidate cache mrc p15, 0, ip, c1, c0, 0 @ get ctrl register - bic ip, ip, #0x0000000c @ ............wc.. + bic ip, ip, #0x000e @ ............wcam mcr p15, 0, ip, c1, c0, 0 @ ctrl register mov pc, r0 - __INIT +/* + * idle mode processing + */ +ENTRY(cpu_arm740_do_idle) + mov pc, lr + +/* + * *FIXME* + */ +ENTRY(cpu_arm740_dcache_clean_area) + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 @ flush cache + mov pc, lr + +/* + * Function: arm740_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, + */ +ENTRY(cpu_arm740_switch_mm) + mov pc, lr - .type __arm740_setup, #function + + /* .section ".text.init", #alloc, #execinstr */ + __INIT + __arm740_setup: mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ invalidate caches - - mcr p15, 0, r0, c6, c3 @ disable area 3~7 - mcr p15, 0, r0, c6, c4 - mcr p15, 0, r0, c6, c5 - mcr p15, 0, r0, c6, c6 - mcr p15, 0, r0, c6, c7 - - mov r0, #0x0000003F @ base = 0, size = 4GB - mcr p15, 0, r0, c6, c0 @ set area 0, default - - ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM - ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the area register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c1 @ set area 1, RAM - - ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH - ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the area register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c2 @ set area 2, ROM/FLASH - - mov r0, #0x06 - mcr p15, 0, r0, c2, c0 @ Region 1&2 cacheable -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r0, #0x00 @ disable whole write buffer -#else - mov r0, #0x02 @ Region 1 write bufferred -#endif - mcr p15, 0, r0, c3, c0 - - mov r0, #0x10000 - sub r0, r0, #1 @ r0 = 0xffff - mcr p15, 0, r0, c5, c0 @ all read/write access + mcr p15, 0, r0, c7, c7, 0 @ invalidate caches - mrc p15, 0, r0, c1, c0 @ get control register - bic r0, r0, #0x3F000000 @ set to standard caching mode - @ need some benchmark - orr r0, r0, #0x0000000d @ MPU/Cache/WB + mov r0, #0x0 @disable region 3-7 + mcr p15, 0, r0, c6, c3 + mcr p15, 0, r0, c6, c4 + mcr p15, 0, r0, c6, c5 + mcr p15, 0, r0, c6, c6 + mcr p15, 0, r0, c6, c7 - mov pc, lr + mov r0, #0x0000003F @ (base = 0, size = 4GB, non cacheable, no write buffer) + mcr p15, 0, r0, c6, c0 @ enable region 0, default + mov r0, #0x00000037 @ (base = 0, size = 256MB, cacheable, write buffered) + mcr p15, 0, r0, c6, c1 @enable region 1, RAM + mov r0, #0x20000000 + add r0, r0, #0x37 @ (base = 512MB, size = 256MB, cacheable, write buffered) + mcr p15, 0, r0, c6, c2 @enable region 2, ROM/Flash + + mov r0, #0x06 + mcr p15, 0, r0, c2, c0 @ Region 1&2 cacheable + mov r0, #0x02 + mcr p15, 0, r0, c3, c0 @ Region 1 write buferred - .size __arm740_setup, . - __arm740_setup + mov r0, #0xff00 + add r0, r0, #0x00ff + mcr p15, 0, r0, c5, c0 @ all read/write access + + mrc p15, 0, r0, c1, c0 @ get control register + orr r0, r0, #0x00030000 @ Split cache mode + orr r0, r0, #0x0000000d @ MPU, Cache, Write Buffer on + + mov pc, lr @ __ret (head-armv.S) + + .size __arm740_setup, . - __arm740_setup __INITDATA @@ -125,18 +286,17 @@ __arm740_setup: */ .type arm740_processor_functions, #object ENTRY(arm740_processor_functions) - .word v4t_late_abort + .word cpu_arm740_data_abort .word cpu_arm740_proc_init .word cpu_arm740_proc_fin .word cpu_arm740_reset .word cpu_arm740_do_idle + .word cpu_arm740_dcache_clean_area .word cpu_arm740_switch_mm - .word 0 @ cpu_*_set_pte .size arm740_processor_functions, . - arm740_processor_functions - .section ".rodata" - + .section ".rodata" .type cpu_arch_name, #object cpu_arch_name: .asciz "armv4" @@ -154,21 +314,23 @@ cpu_arm740_name: .align + .section ".proc.info.init", #alloc, #execinstr .type __arm740_proc_info,#object __arm740_proc_info: .long 0x41807400 .long 0xfffffff0 .long 0 + .long 0 b __arm740_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT - .long cpu_arm740_name - .long arm740_processor_functions + .long cpu_arm740_name + .long arm740_processor_functions .long 0 .long 0 - .long v3_cache_fns @ cache model + .long v4_cache_fns @ cache model .size __arm740_proc_info, . - __arm740_proc_info diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S index 22d7e310..912491a0 100644 --- a/arch/arm/mm/proc-arm7tdmi.S +++ b/arch/arm/mm/proc-arm7tdmi.S @@ -1,57 +1,218 @@ /* - * linux/arch/arm/mm/proc-arm7tdmi.S: utility functions for ARM7TDMI + * linux/arch/arm/mm/proc-arm7tdmi.S * - * Copyright (C) 2003-2006 Hyok S. Choi + * Copyright (C) 1997-2000 Russell King + * Copyright (C) 2003 Hyok S. Choi * * 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. * + * for ARM7TDMI and the compatibles. */ #include #include #include -#include -#include #include #include #include +#include + +ENTRY(cpu_arm7tdmi_dcache_clean_area) + mov pc, lr - .text /* - * cpu_arm7tdmi_proc_init() - * cpu_arm7tdmi_do_idle() - * cpu_arm7tdmi_dcache_clean_area() - * cpu_arm7tdmi_switch_mm() + * Function: arm7tdmi_data_abort () + * + * Params : r2 = address of aborted instruction + * : sp = pointer to registers * - * These are not required. + * Purpose : obtain information about current aborted instruction + * + * Returns : r0 = address of abort + * : r1 = FSR */ -ENTRY(cpu_arm7tdmi_proc_init) -ENTRY(cpu_arm7tdmi_do_idle) -ENTRY(cpu_arm7tdmi_dcache_clean_area) -ENTRY(cpu_arm7tdmi_switch_mm) - mov pc, lr + +ENTRY(cpu_arm7tdmi_data_abort) +#ifdef CONFIG_CPU_CP15 + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR +#endif + ldr r8, [r0] @ read arm instruction + tst r8, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + and r7, r8, #15 << 24 + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_unknown +/* 1 */ mov pc, lr @ swp +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r6 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? /* - * cpu_arm7tdmi_proc_fin() + * Function: arm7tdmi_proc_init (void) + * : arm7tdmi_proc_fin (void) + * + * Notes : This processor does not require these */ +ENTRY(cpu_arm7tdmi_proc_init) + mov pc, lr + ENTRY(cpu_arm7tdmi_proc_fin) mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, r0 +#ifdef CONFIG_CPU_CP15 + mov r0, #0x31 @ ....S..DP...M + mcr p15, 0, r0, c1, c0, 0 @ disable caches +#endif + mov pc, lr + +ENTRY(cpu_arm7tdmi_do_idle) + mov pc, lr + +/* + * Function: arm7tdmi_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, saving the old processes state, and restoring + * the new. + */ +ENTRY(cpu_arm7tdmi_switch_mm) mov pc, lr /* - * Function: cpu_arm7tdmi_reset(loc) - * Params : loc(r0) address to jump to - * Purpose : Sets up everything for a reset and jump to the location for soft reset. + * Function: _arm7tdmi_reset + * Params : r0 = address to jump to + * Notes : This sets up everything for a reset */ ENTRY(cpu_arm7tdmi_reset) +#ifdef CONFIG_CPU_CP15 + mov r1, #0 + mcr p15, 0, r1, c7, c0, 0 @ flush cache + mov r1, #0x30 + mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc +#endif mov pc, r0 __INIT .type __arm7tdmi_setup, #function __arm7tdmi_setup: +#ifdef CONFIG_CPU_CP15 + mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 +#endif + mov r0, #0x7c @ . .... .LDP WC.. mov pc, lr .size __arm7tdmi_setup, . - __arm7tdmi_setup @@ -63,26 +224,23 @@ __arm7tdmi_setup: */ .type arm7tdmi_processor_functions, #object ENTRY(arm7tdmi_processor_functions) - .word v4t_late_abort + .word cpu_arm7tdmi_data_abort .word cpu_arm7tdmi_proc_init .word cpu_arm7tdmi_proc_fin .word cpu_arm7tdmi_reset .word cpu_arm7tdmi_do_idle .word cpu_arm7tdmi_dcache_clean_area .word cpu_arm7tdmi_switch_mm - .word 0 @ cpu_*_set_pte .size arm7tdmi_processor_functions, . - arm7tdmi_processor_functions .section ".rodata" .type cpu_arch_name, #object -cpu_arch_name: - .asciz "armv4t" +cpu_arch_name: .asciz "armv4t" .size cpu_arch_name, . - cpu_arch_name .type cpu_elf_name, #object -cpu_elf_name: - .asciz "v4" +cpu_elf_name: .asciz "v4" .size cpu_elf_name, . - cpu_elf_name .type cpu_arm7tdmi_name, #object @@ -92,7 +250,11 @@ cpu_arm7tdmi_name: .type cpu_triscenda7_name, #object cpu_triscenda7_name: - .asciz "Triscend-A7x" +#if defined(CONFIG_ARCH_TA7S) + .asciz "Triscend-A7S" +#elif defined(CONFIG_ARCH_TA7V) + .asciz "Triscend-A7V" +#endif .size cpu_triscenda7_name, . - cpu_triscenda7_name .type cpu_at91_name, #object @@ -192,9 +354,9 @@ __s3c4510b_proc_info: .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT .long cpu_s3c4510b_name .long arm7tdmi_processor_functions + .long v4_cache_fns .long 0 .long 0 - .long v4_cache_fns .size __s3c4510b_proc_info, . - __s3c4510b_proc_info .type __s3c4530_proc_info, #object diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 571f082f..d2e64e83 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -39,7 +39,12 @@ /* * The size of one data cache line. */ -#define CACHE_DLINESIZE 32 +#define CACHE_DLINESIZE 16 +#if 1 /* add by Victor Yu. 02-08-2007 */ +#define CACHE_DSIZE 16384 +#define CACHE_ISIZE 16384 +#define CACHE_ILINESIZE 16 +#endif /* * The number of data cache segments. @@ -105,6 +110,9 @@ ENTRY(cpu_arm922_reset) mrc p15, 0, ip, c1, c0, 0 @ ctrl register bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x1100 @ ...i...s........ +#if 1 /* add by Victor Yu. 06-09-2005 */ + bic ip, ip, #0x0800 @ off BTB +#endif mcr p15, 0, ip, c1, c0, 0 @ ctrl register mov pc, r0 @@ -113,7 +121,9 @@ ENTRY(cpu_arm922_reset) */ .align 5 ENTRY(cpu_arm922_do_idle) +#if 0 /* mask by Victor Yu. 02-08-2007 */ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif mov pc, lr @@ -134,6 +144,7 @@ ENTRY(arm922_flush_user_cache_all) * Clean and invalidate the entire cache. */ ENTRY(arm922_flush_kern_cache_all) +#if 1 /* mask by Victor Yu. 05-30-2005 */ mov r2, #VM_EXEC mov ip, #0 __flush_whole_cache: @@ -148,6 +159,29 @@ __flush_whole_cache: mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache mcrne p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 05-30-2005 */ + mov ip, #0 + +#ifndef CONFIG_CPU_ICACHE_DISABLE + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache +#endif + +__flush_whole_cache: + +#ifndef CONFIG_CPU_DCACHE_DISABLE + mov ip, #0 +# ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +# else + mcr p15, 0, ip, c7,c14, 0 @ clean/invalidate D cache +# endif +#endif /*CONFIG_CPU_DCACHE_DISABLE*/ + +#ifndef CONFIG_CPU_FA_WB_DISABLE + mcr p15, 0, ip, c7, c10, 4 @ drain write buffer +#endif + mov pc, lr +#endif /* * flush_user_cache_range(start, end, flags) @@ -160,6 +194,7 @@ __flush_whole_cache: * - flags - vm_flags describing address space */ ENTRY(arm922_flush_user_cache_range) +#if 1 /* mask by Victor Yu. 05-30-2005 */ mov ip, #0 sub r3, r1, r0 @ calculate total size cmp r3, #CACHE_DLIMIT @@ -174,6 +209,61 @@ ENTRY(arm922_flush_user_cache_range) tst r2, #VM_EXEC mcrne p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 05-30-2005 */ + mov ip, #0 + sub r3, r1, r0 @ calculate total size +#ifndef CONFIG_CPU_ICACHE_DISABLE + tst r2, #VM_EXEC @ executable region? + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache +#endif + +#ifndef CONFIG_CPU_DCACHE_DISABLE + cmp r3, #CACHE_DSIZE @ total size >= limit? + bhs __flush_whole_cache @ flush whole D cache + +1: + +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry +#endif + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + bls 1b +#endif /* CONFIG_CPU_DCACHE_DISABLE */ + +#ifndef CONFIG_CPU_FA_WB_DISABLE + tst r2, #VM_EXEC + mcreq p15, 0, r4, c7, c10, 4 @ drain write buffer +#endif + + mov pc, lr +#endif + +/* + * flush_kern_dcache_page(void *page) + * + * Ensure no D cache aliasing occurs, either with itself or + * the I cache + * + * - addr - page aligned address + */ +ENTRY(arm922_flush_kern_dcache_page) +#if 1 /* mask by Victor Yu. 05-30-2005 */ + add r1, r0, #PAGE_SZ +1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr +#else /* add by Victor Yu. 05-30-2005 */ + add r1, r0, #PAGE_SZ + /* fall through */ +#endif /* * coherent_kern_range(start, end) @@ -199,6 +289,7 @@ ENTRY(arm922_coherent_kern_range) * - end - virtual end address */ ENTRY(arm922_coherent_user_range) +#if 1 /* mask by Victor Yu. 06-09-2005 */ bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry @@ -207,25 +298,35 @@ ENTRY(arm922_coherent_user_range) blo 1b mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 06-09-2005 */ + bic r0, r0, #CACHE_DLINESIZE-1 -/* - * flush_kern_dcache_page(void *page) - * - * Ensure no D cache aliasing occurs, either with itself or - * the I cache - * - * - addr - page aligned address - */ -ENTRY(arm922_flush_kern_dcache_page) - add r1, r0, #PAGE_SZ -1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr +#if !(defined(CONFIG_CPU_DCACHE_DISABLE) && defined(CONFIG_CPU_ICACHE_DISABLE)) +1: +#ifndef CONFIG_CPU_DCACHE_DISABLE +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry +#endif +#endif /* CONFIG_CPU_DCACHE_DISABLE */ + +#ifndef CONFIG_CPU_ICACHE_DISABLE + mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry +#endif + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + bls 1b @ Luke Lee 05/19/2005 blo->bls +#endif /* !(defined(CONFIG_CPU_DCACHE_DISABLE) && defined(CONFIG_CPU_ICACHE_DISABLE)) */ + + mov ip, #0 + +#ifndef CONFIG_CPU_FA_WB_DISABLE + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#endif + + mov pc, lr +#endif /* * dma_inv_range(start, end) @@ -241,6 +342,7 @@ ENTRY(arm922_flush_kern_dcache_page) * (same as v4wb) */ ENTRY(arm922_dma_inv_range) +#if 1 /* mask by Victor Yu. 05-30-2005 */ tst r0, #CACHE_DLINESIZE - 1 bic r0, r0, #CACHE_DLINESIZE - 1 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -252,6 +354,30 @@ ENTRY(arm922_dma_inv_range) blo 1b mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 05-30-2005 */ +#ifndef CONFIG_CPU_DCACHE_DISABLE + +# ifndef CONFIG_CPU_DCACHE_WRITETHROUGH + tst r0, #CACHE_DLINESIZE -1 + bic r0, r0, #CACHE_DLINESIZE -1 + mcrne p15, 0, r0, c7, c10, 1 @ clean boundary D entry + mcr p15, 0, r1, c7, c10, 1 @ clean boundary D entry +# else + bic r0, r0, #CACHE_DLINESIZE -1 +# endif /* CONFIG_CPU_DCACHE_WRITETHROUGH */ + +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + bls 1b @ Luke Lee 05/19/2005 blo->bls +#endif /* CONFIG_CPU_DCACHE_DISABLE */ + +#ifndef CONFIG_CPU_FA_WB_DISABLE + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer +#endif + mov pc, lr +#endif /* * dma_clean_range(start, end) @@ -264,6 +390,7 @@ ENTRY(arm922_dma_inv_range) * (same as v4wb) */ ENTRY(arm922_dma_clean_range) +#if 1 /* mask by Victor Yu. 05-30-2005 */ bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #CACHE_DLINESIZE @@ -271,6 +398,24 @@ ENTRY(arm922_dma_clean_range) blo 1b mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 05-30-2005 */ +#ifndef CONFIG_CPU_DCACHE_DISABLE +#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH + bic r0, r0, #CACHE_DLINESIZE - 1 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + cmp r0, r1 + bls 1b @ Luke Lee 05/19/2005 blo->bls + +#endif /* CONFIG_CPU_DCACHE_WRITETHROUGH */ +#endif /* CONFIG_CPU_DCACHE_DISABLE */ + +#ifndef CONFIG_CPU_FA_WB_DISABLE + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer +#endif + mov pc, lr +#endif /* * dma_flush_range(start, end) @@ -280,6 +425,7 @@ ENTRY(arm922_dma_clean_range) * - start - virtual start address * - end - virtual end address */ +#if 1 /* mask by Victor Yu. 06-09-2005 */ ENTRY(arm922_dma_flush_range) bic r0, r0, #CACHE_DLINESIZE - 1 1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry @@ -288,6 +434,10 @@ ENTRY(arm922_dma_flush_range) blo 1b mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr +#else /* add by Victor Yu. 06-09-2005 */ + .globl arm922_dma_flush_range + .set arm922_dma_flush_range, arm922_coherent_kern_range +#endif ENTRY(arm922_cache_fns) .long arm922_flush_kern_cache_all @@ -299,6 +449,9 @@ ENTRY(arm922_cache_fns) .long arm922_dma_inv_range .long arm922_dma_clean_range .long arm922_dma_flush_range +#if 1 /* add by Victor Yu. 06-09-2005 */ + .size arm922_cache_fns, . - arm922_cache_fns +#endif #endif @@ -420,7 +573,11 @@ arm922_crval: */ .type arm922_processor_functions, #object arm922_processor_functions: +#if 0 /* mask by Victor Yu. 02-08-2007 */ .word v4t_early_abort +#else + .word nommu_early_abort +#endif .word cpu_arm922_proc_init .word cpu_arm922_proc_fin .word cpu_arm922_reset @@ -453,8 +610,13 @@ cpu_arm922_name: .type __arm922_proc_info,#object __arm922_proc_info: +#if 0 /* mask by Victor Yu. 02-08-2007 */ .long 0x41009220 .long 0xff00fff0 +#else + .long 0x66015261 + .long 0xff01fff1 +#endif .long PMD_TYPE_SECT | \ PMD_SECT_BUFFERABLE | \ PMD_SECT_CACHEABLE | \ diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index 8d9a9f93..3b4bd1fc 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -5,6 +5,8 @@ * Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2002 RidgeRun, Inc. * Copyright (C) 2002-2003 MontaVista Software, Inc. + * Copyright (C) 2003 Hyok S. Choi + * modified for NON-PAGED MMU version. * * Update for Linux-2.6 and cache flush improvements * Copyright (C) 2004 Nokia Corporation by Tony Lindgren @@ -390,6 +392,7 @@ ENTRY(cpu_arm925_switch_mm) #endif mov pc, lr +#ifdef CONFIG_MMU /* * cpu_arm925_set_pte(ptep, pte) * @@ -428,7 +431,7 @@ ENTRY(cpu_arm925_set_pte) mcr p15, 0, r0, c7, c10, 4 @ drain WB #endif /* CONFIG_MMU */ mov pc, lr - +#endif /* CONFIG_MMU */ __INIT .type __arm925_setup, #function @@ -490,7 +493,9 @@ arm925_processor_functions: .word cpu_arm925_do_idle .word cpu_arm925_dcache_clean_area .word cpu_arm925_switch_mm +#ifdef CONFIG_MMU .word cpu_arm925_set_pte +#endif .size arm925_processor_functions, . - arm925_processor_functions .section ".rodata" diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S dissimilarity index 80% index 2397f4b6..e88fc3a4 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S @@ -1,369 +1,218 @@ -/* - * linux/arch/arm/mm/arm940.S: utility functions for ARM940T - * - * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@samsung.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. - * - */ -#include -#include -#include -#include -#include -#include -#include - -/* ARM940T has a 4KB DCache comprising 256 lines of 4 words */ -#define CACHE_DLINESIZE 16 -#define CACHE_DSEGMENTS 4 -#define CACHE_DENTRIES 64 - - .text -/* - * cpu_arm940_proc_init() - * cpu_arm940_switch_mm() - * - * These are not required. - */ -ENTRY(cpu_arm940_proc_init) -ENTRY(cpu_arm940_switch_mm) - mov pc, lr - -/* - * cpu_arm940_proc_fin() - */ -ENTRY(cpu_arm940_proc_fin) - stmfd sp!, {lr} - mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE - msr cpsr_c, ip - bl arm940_flush_kern_cache_all - mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #0x00001000 @ i-cache - bic r0, r0, #0x00000004 @ d-cache - mcr p15, 0, r0, c1, c0, 0 @ disable caches - ldmfd sp!, {pc} - -/* - * cpu_arm940_reset(loc) - * Params : r0 = address to jump to - * Notes : This sets up everything for a reset - */ -ENTRY(cpu_arm940_reset) - mov ip, #0 - mcr p15, 0, ip, c7, c5, 0 @ flush I cache - mcr p15, 0, ip, c7, c6, 0 @ flush D cache - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mrc p15, 0, ip, c1, c0, 0 @ ctrl register - bic ip, ip, #0x00000005 @ .............c.p - bic ip, ip, #0x00001000 @ i-cache - mcr p15, 0, ip, c1, c0, 0 @ ctrl register - mov pc, r0 - -/* - * cpu_arm940_do_idle() - */ - .align 5 -ENTRY(cpu_arm940_do_idle) - mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt - mov pc, lr - -/* - * flush_user_cache_all() - */ -ENTRY(arm940_flush_user_cache_all) - /* FALLTHROUGH */ - -/* - * flush_kern_cache_all() - * - * Clean and invalidate the entire cache. - */ -ENTRY(arm940_flush_kern_cache_all) - mov r2, #VM_EXEC - /* FALLTHROUGH */ - -/* - * flush_user_cache_range(start, end, flags) - * - * There is no efficient way to flush a range of cache entries - * in the specified address range. Thus, flushes all. - * - * - start - start address (inclusive) - * - end - end address (exclusive) - * - flags - vm_flags describing address space - */ -ENTRY(arm940_flush_user_cache_range) - mov ip, #0 -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, ip, c7, c6, 0 @ flush D cache -#else - mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries -2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 4 - bcs 1b @ segments 3 to 0 -#endif - tst r2, #VM_EXEC - mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache - mcrne p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * coherent_kern_range(start, end) - * - * Ensure coherency between the Icache and the Dcache in the - * region described by start, end. If you have non-snooping - * Harvard caches, you need to implement this function. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm940_coherent_kern_range) - /* FALLTHROUGH */ - -/* - * coherent_user_range(start, end) - * - * Ensure coherency between the Icache and the Dcache in the - * region described by start, end. If you have non-snooping - * Harvard caches, you need to implement this function. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm940_coherent_user_range) - /* FALLTHROUGH */ - -/* - * flush_kern_dcache_page(void *page) - * - * Ensure no D cache aliasing occurs, either with itself or - * the I cache - * - * - addr - page aligned address - */ -ENTRY(arm940_flush_kern_dcache_page) - mov ip, #0 - mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries -2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 4 - bcs 1b @ segments 7 to 0 - mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_inv_range(start, end) - * - * There is no efficient way to invalidate a specifid virtual - * address range. Thus, invalidates all. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm940_dma_inv_range) - mov ip, #0 - mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries -2: mcr p15, 0, r3, c7, c6, 2 @ flush D entry - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 4 - bcs 1b @ segments 7 to 0 - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_clean_range(start, end) - * - * There is no efficient way to clean a specifid virtual - * address range. Thus, cleans all. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm940_dma_clean_range) -ENTRY(cpu_arm940_dcache_clean_area) - mov ip, #0 -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries -2: mcr p15, 0, r3, c7, c10, 2 @ clean D entry - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 4 - bcs 1b @ segments 7 to 0 -#endif - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_flush_range(start, end) - * - * There is no efficient way to clean and invalidate a specifid - * virtual address range. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm940_dma_flush_range) - mov ip, #0 - mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries -2: -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r3, c7, c14, 2 @ clean/flush D entry -#else - mcr p15, 0, r3, c7, c10, 2 @ clean D entry -#endif - subs r3, r3, #1 << 26 - bcs 2b @ entries 63 to 0 - subs r1, r1, #1 << 4 - bcs 1b @ segments 7 to 0 - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -ENTRY(arm940_cache_fns) - .long arm940_flush_kern_cache_all - .long arm940_flush_user_cache_all - .long arm940_flush_user_cache_range - .long arm940_coherent_kern_range - .long arm940_coherent_user_range - .long arm940_flush_kern_dcache_page - .long arm940_dma_inv_range - .long arm940_dma_clean_range - .long arm940_dma_flush_range - - __INIT - - .type __arm940_setup, #function -__arm940_setup: - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache - mcr p15, 0, r0, c7, c10, 4 @ drain WB - - mcr p15, 0, r0, c6, c3, 0 @ disable data area 3~7 - mcr p15, 0, r0, c6, c4, 0 - mcr p15, 0, r0, c6, c5, 0 - mcr p15, 0, r0, c6, c6, 0 - mcr p15, 0, r0, c6, c7, 0 - - mcr p15, 0, r0, c6, c3, 1 @ disable instruction area 3~7 - mcr p15, 0, r0, c6, c4, 1 - mcr p15, 0, r0, c6, c5, 1 - mcr p15, 0, r0, c6, c6, 1 - mcr p15, 0, r0, c6, c7, 1 - - mov r0, #0x0000003F @ base = 0, size = 4GB - mcr p15, 0, r0, c6, c0, 0 @ set area 0, default - mcr p15, 0, r0, c6, c0, 1 - - ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM - ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the area register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c1, 0 @ set area 1, RAM - mcr p15, 0, r0, c6, c1, 1 - - ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH - ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the area register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c2, 0 @ set area 2, ROM/FLASH - mcr p15, 0, r0, c6, c2, 1 - - mov r0, #0x06 - mcr p15, 0, r0, c2, c0, 0 @ Region 1&2 cacheable - mcr p15, 0, r0, c2, c0, 1 -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r0, #0x00 @ disable whole write buffer -#else - mov r0, #0x02 @ Region 1 write bufferred -#endif - mcr p15, 0, r0, c3, c0, 0 - - mov r0, #0x10000 - sub r0, r0, #1 @ r0 = 0xffff - mcr p15, 0, r0, c5, c0, 0 @ all read/write access - mcr p15, 0, r0, c5, c0, 1 - - mrc p15, 0, r0, c1, c0 @ get control register - orr r0, r0, #0x00001000 @ I-cache - orr r0, r0, #0x00000005 @ MPU/D-cache - - mov pc, lr - - .size __arm940_setup, . - __arm940_setup - - __INITDATA - -/* - * Purpose : Function pointers used to access above functions - all calls - * come through these - */ - .type arm940_processor_functions, #object -ENTRY(arm940_processor_functions) - .word nommu_early_abort - .word cpu_arm940_proc_init - .word cpu_arm940_proc_fin - .word cpu_arm940_reset - .word cpu_arm940_do_idle - .word cpu_arm940_dcache_clean_area - .word cpu_arm940_switch_mm - .word 0 @ cpu_*_set_pte - .size arm940_processor_functions, . - arm940_processor_functions - - .section ".rodata" - -.type cpu_arch_name, #object -cpu_arch_name: - .asciz "armv4t" - .size cpu_arch_name, . - cpu_arch_name - - .type cpu_elf_name, #object -cpu_elf_name: - .asciz "v4" - .size cpu_elf_name, . - cpu_elf_name - - .type cpu_arm940_name, #object -cpu_arm940_name: - .ascii "ARM940T" - .size cpu_arm940_name, . - cpu_arm940_name - - .align - - .section ".proc.info.init", #alloc, #execinstr - - .type __arm940_proc_info,#object -__arm940_proc_info: - .long 0x41009400 - .long 0xff00fff0 - .long 0 - b __arm940_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB - .long cpu_arm940_name - .long arm940_processor_functions - .long 0 - .long 0 - .long arm940_cache_fns - .size __arm940_proc_info, . - __arm940_proc_info - +/* + * linux/arch/armnommu/mm/arm940.S: MPU functions for ARM940 + * 2001 Minspeed + * + * 2004/03/22 modified for 2.6 kernel by heechul.yun@samsung.com + * 2004/04/20 clean-up by Hyok S. Choi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "proc-macros.S" + + /* FIXME - this is also defined in cache-v4wb.S */ +#define CACHE_DSIZE 4096 /* 4K */ +#define CACHE_DLINESIZE 16 /* 4word */ +#define CACHE_DLIMIT (CACHE_DSIZE * 4) + +/* + * cpu_arm940_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm940_data_abort) + mrc p15, 0, r3, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r1, [r0] @ read aborted instruction + tst r1, r1, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm940_check_bugs() + */ +ENTRY(cpu_arm940_check_bugs) + mrs ip, cpsr + bic ip, ip, #PSR_F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm940_proc_init() + * + * setup_processor() - setup.c + * +-> cpu_proc_init() - cpu-multi32.h --> proc-arm940.S + * + * TODO: cp15 initialization code can be placed here - hcyun + */ +ENTRY(cpu_arm940_proc_init) + mov pc, lr + +/* + * cpu_arm940_proc_fin() + */ +ENTRY(cpu_arm940_proc_fin) + stmfd sp!, {lr} + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, ip +#if defined(CONFIG_CPU_CACHE_V4WT) + bl v4wt_flush_kern_cache_all @ write-through +#elif defined(CONFIG_CPU_CACHE_V4WB) + bl v4wb_flush_kern_cache_all @ write-back +#endif /* CONFIG_CPU_CACHE_V4WT */ + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm940_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ +ENTRY(cpu_arm940_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * idle mode processing + */ +ENTRY(cpu_arm940_do_idle) +#if defined(CONFIG_CPU_ARM940_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* + * *FIXME* + */ +ENTRY(cpu_arm940_dcache_clean_area) +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + subs r1, r1, #CACHE_DLINESIZE + bhi 1b + mov pc, lr +/* + * Function: arm940_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, + */ +ENTRY(cpu_arm940_switch_mm) + mov pc, lr + + + /* .section ".text.init", #alloc, #execinstr */ + __INIT + +__arm940_setup: + MRC p15, 0, R0, c1, c0, 0 @ get control register + +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + bic r0, r0, #0x000c @ W,D + bic r0, r0, #0x1000 @ I +/* + * Turn on what we want + */ +#ifdef CONFIG_CPU_MXU_ENABLE + orr r0, r0, #0x0001 @ Enable PU +#else + bic r0, r0, #0x0001 @ Disable PU +#endif + +#ifdef CONFIG_CPU_ARM940_D_CACHE_ON + orr r0, r0, #0x0004 @ Enable D cache +#endif +#ifdef CONFIG_CPU_ARM940_I_CACHE_ON + orr r0, r0, #0x1000 @ I Cache on +#endif + mov pc, lr + .size __arm940_setup, . - __arm940_setup + + __INITDATA + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm940_processor_functions, #object +ENTRY(arm940_processor_functions) + .word cpu_arm940_data_abort + .word cpu_arm940_proc_init + .word cpu_arm940_proc_fin + .word cpu_arm940_reset + .word cpu_arm940_do_idle + + .word cpu_arm940_dcache_clean_area + .word cpu_arm940_switch_mm + .size arm940_processor_functions, . - arm940_processor_functions + + .section ".rodata" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm940_name, #object +cpu_arm940_name: + .ascii "ARM940T" + .size cpu_arm940_name, . - cpu_arm940_name + + .align + + + .section ".proc.info.init", #alloc, #execinstr + .type __arm940_proc_info,#object +__arm940_proc_info: + .long 0x41009400 + .long 0xff00fff0 + .long 0 + .long 0 + b __arm940_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm940_name + .long arm940_processor_functions + .long 0 + .long 0 +#if defined(CONFIG_CPU_CACHE_V4WT) + .long v4wt_cache_fns @ cache model +#elif defined(CONFIG_CPU_CACHE_V4WB) + .long v4wb_cache_fns @ cache model +#endif /* CONFIG_CPU_CACHE_V4WT */ + .size __arm940_proc_info, . - __arm940_proc_info + diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S dissimilarity index 81% index e1861756..f3d8ad8e 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S @@ -1,424 +1,215 @@ -/* - * linux/arch/arm/mm/arm946.S: utility functions for ARM946E-S - * - * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@samsung.com) - * - * (Many of cache codes are from proc-arm926.S) - * - * 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 -#include -#include -#include -#include -#include -#include - -/* - * ARM946E-S is synthesizable to have 0KB to 1MB sized D-Cache, - * comprising 256 lines of 32 bytes (8 words). - */ -#define CACHE_DSIZE (CONFIG_CPU_DCACHE_SIZE) /* typically 8KB. */ -#define CACHE_DLINESIZE 32 /* fixed */ -#define CACHE_DSEGMENTS 4 /* fixed */ -#define CACHE_DENTRIES (CACHE_DSIZE / CACHE_DSEGMENTS / CACHE_DLINESIZE) -#define CACHE_DLIMIT (CACHE_DSIZE * 4) /* benchmark needed */ - - .text -/* - * cpu_arm946_proc_init() - * cpu_arm946_switch_mm() - * - * These are not required. - */ -ENTRY(cpu_arm946_proc_init) -ENTRY(cpu_arm946_switch_mm) - mov pc, lr - -/* - * cpu_arm946_proc_fin() - */ -ENTRY(cpu_arm946_proc_fin) - stmfd sp!, {lr} - mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE - msr cpsr_c, ip - bl arm946_flush_kern_cache_all - mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #0x00001000 @ i-cache - bic r0, r0, #0x00000004 @ d-cache - mcr p15, 0, r0, c1, c0, 0 @ disable caches - ldmfd sp!, {pc} - -/* - * cpu_arm946_reset(loc) - * Params : r0 = address to jump to - * Notes : This sets up everything for a reset - */ -ENTRY(cpu_arm946_reset) - mov ip, #0 - mcr p15, 0, ip, c7, c5, 0 @ flush I cache - mcr p15, 0, ip, c7, c6, 0 @ flush D cache - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mrc p15, 0, ip, c1, c0, 0 @ ctrl register - bic ip, ip, #0x00000005 @ .............c.p - bic ip, ip, #0x00001000 @ i-cache - mcr p15, 0, ip, c1, c0, 0 @ ctrl register - mov pc, r0 - -/* - * cpu_arm946_do_idle() - */ - .align 5 -ENTRY(cpu_arm946_do_idle) - mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt - mov pc, lr - -/* - * flush_user_cache_all() - */ -ENTRY(arm946_flush_user_cache_all) - /* FALLTHROUGH */ - -/* - * flush_kern_cache_all() - * - * Clean and invalidate the entire cache. - */ -ENTRY(arm946_flush_kern_cache_all) - mov r2, #VM_EXEC - mov ip, #0 -__flush_whole_cache: -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, ip, c7, c6, 0 @ flush D cache -#else - mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments -1: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries -2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index - subs r3, r3, #1 << 4 - bcs 2b @ entries n to 0 - subs r1, r1, #1 << 29 - bcs 1b @ segments 3 to 0 -#endif - tst r2, #VM_EXEC - mcrne p15, 0, ip, c7, c5, 0 @ flush I cache - mcrne p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * flush_user_cache_range(start, end, flags) - * - * Clean and invalidate a range of cache entries in the - * specified address range. - * - * - start - start address (inclusive) - * - end - end address (exclusive) - * - flags - vm_flags describing address space - * (same as arm926) - */ -ENTRY(arm946_flush_user_cache_range) - mov ip, #0 - sub r3, r1, r0 @ calculate total size - cmp r3, #CACHE_DLIMIT - bhs __flush_whole_cache - -1: tst r2, #VM_EXEC -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry - add r0, r0, #CACHE_DLINESIZE - mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry - add r0, r0, #CACHE_DLINESIZE -#else - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry - mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry - add r0, r0, #CACHE_DLINESIZE - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry - mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry - add r0, r0, #CACHE_DLINESIZE -#endif - cmp r0, r1 - blo 1b - tst r2, #VM_EXEC - mcrne p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * coherent_kern_range(start, end) - * - * Ensure coherency between the Icache and the Dcache in the - * region described by start, end. If you have non-snooping - * Harvard caches, you need to implement this function. - * - * - start - virtual start address - * - end - virtual end address - */ -ENTRY(arm946_coherent_kern_range) - /* FALLTHROUGH */ - -/* - * coherent_user_range(start, end) - * - * Ensure coherency between the Icache and the Dcache in the - * region described by start, end. If you have non-snooping - * Harvard caches, you need to implement this function. - * - * - start - virtual start address - * - end - virtual end address - * (same as arm926) - */ -ENTRY(arm946_coherent_user_range) - bic r0, r0, #CACHE_DLINESIZE - 1 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * flush_kern_dcache_page(void *page) - * - * Ensure no D cache aliasing occurs, either with itself or - * the I cache - * - * - addr - page aligned address - * (same as arm926) - */ -ENTRY(arm946_flush_kern_dcache_page) - add r1, r0, #PAGE_SZ -1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_inv_range(start, end) - * - * Invalidate (discard) the specified virtual address range. - * May not write back any entries. If 'start' or 'end' - * are not cache line aligned, those lines must be written - * back. - * - * - start - virtual start address - * - end - virtual end address - * (same as arm926) - */ -ENTRY(arm946_dma_inv_range) -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - tst r0, #CACHE_DLINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #CACHE_DLINESIZE - 1 - mcrne p15, 0, r1, c7, c10, 1 @ clean D entry -#endif - bic r0, r0, #CACHE_DLINESIZE - 1 -1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_clean_range(start, end) - * - * Clean the specified virtual address range. - * - * - start - virtual start address - * - end - virtual end address - * - * (same as arm926) - */ -ENTRY(arm946_dma_clean_range) -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - bic r0, r0, #CACHE_DLINESIZE - 1 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b -#endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * dma_flush_range(start, end) - * - * Clean and invalidate the specified virtual address range. - * - * - start - virtual start address - * - end - virtual end address - * - * (same as arm926) - */ -ENTRY(arm946_dma_flush_range) - bic r0, r0, #CACHE_DLINESIZE - 1 -1: -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry -#else - mcr p15, 0, r0, c7, c10, 1 @ clean D entry -#endif - add r0, r0, #CACHE_DLINESIZE - cmp r0, r1 - blo 1b - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -ENTRY(arm946_cache_fns) - .long arm946_flush_kern_cache_all - .long arm946_flush_user_cache_all - .long arm946_flush_user_cache_range - .long arm946_coherent_kern_range - .long arm946_coherent_user_range - .long arm946_flush_kern_dcache_page - .long arm946_dma_inv_range - .long arm946_dma_clean_range - .long arm946_dma_flush_range - - -ENTRY(cpu_arm946_dcache_clean_area) -#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #CACHE_DLINESIZE - subs r1, r1, #CACHE_DLINESIZE - bhi 1b -#endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - - __INIT - - .type __arm946_setup, #function -__arm946_setup: - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache - mcr p15, 0, r0, c7, c10, 4 @ drain WB - - mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7 - mcr p15, 0, r0, c6, c4, 0 - mcr p15, 0, r0, c6, c5, 0 - mcr p15, 0, r0, c6, c6, 0 - mcr p15, 0, r0, c6, c7, 0 - - mov r0, #0x0000003F @ base = 0, size = 4GB - mcr p15, 0, r0, c6, c0, 0 @ set region 0, default - - ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM - ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the region register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM - - ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH - ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) - mov r2, #10 @ 11 is the minimum (4KB) -1: add r2, r2, #1 @ area size *= 2 - mov r1, r1, lsr #1 - bne 1b @ count not zero r-shift - orr r0, r0, r2, lsl #1 @ the region register value - orr r0, r0, #1 @ set enable bit - mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH - - mov r0, #0x06 - mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable - mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r0, #0x00 @ disable whole write buffer -#else - mov r0, #0x02 @ region 1 write bufferred -#endif - mcr p15, 0, r0, c3, c0, 0 - -/* - * Access Permission Settings for future permission control by PU. - * - * priv. user - * region 0 (whole) rw -- : b0001 - * region 1 (RAM) rw rw : b0011 - * region 2 (FLASH) rw r- : b0010 - * region 3~7 (none) -- -- : b0000 - */ - mov r0, #0x00000031 - orr r0, r0, #0x00000200 - mcr p15, 0, r0, c5, c0, 2 @ set data access permission - mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission - - mrc p15, 0, r0, c1, c0 @ get control register - orr r0, r0, #0x00001000 @ I-cache - orr r0, r0, #0x00000005 @ MPU/D-cache -#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN - orr r0, r0, #0x00004000 @ .1.. .... .... .... -#endif - mov pc, lr - - .size __arm946_setup, . - __arm946_setup - - __INITDATA - -/* - * Purpose : Function pointers used to access above functions - all calls - * come through these - */ - .type arm946_processor_functions, #object -ENTRY(arm946_processor_functions) - .word nommu_early_abort - .word cpu_arm946_proc_init - .word cpu_arm946_proc_fin - .word cpu_arm946_reset - .word cpu_arm946_do_idle - - .word cpu_arm946_dcache_clean_area - .word cpu_arm946_switch_mm - .word 0 @ cpu_*_set_pte - .size arm946_processor_functions, . - arm946_processor_functions - - .section ".rodata" - - .type cpu_arch_name, #object -cpu_arch_name: - .asciz "armv5te" - .size cpu_arch_name, . - cpu_arch_name - - .type cpu_elf_name, #object -cpu_elf_name: - .asciz "v5t" - .size cpu_elf_name, . - cpu_elf_name - - .type cpu_arm946_name, #object -cpu_arm946_name: - .ascii "ARM946E-S" - .size cpu_arm946_name, . - cpu_arm946_name - - .align - - .section ".proc.info.init", #alloc, #execinstr - .type __arm946_proc_info,#object -__arm946_proc_info: - .long 0x41009460 - .long 0xff00fff0 - .long 0 - b __arm946_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB - .long cpu_arm946_name - .long arm946_processor_functions - .long 0 - .long 0 - .long arm940_cache_fns - .size __arm946_proc_info, . - __arm946_proc_info - +/* + * linux/arch/armnommu/mm/arm946.S: MPU functions for ARM946E-S + * + * Copyright 2003, STMicroelectronics + * Copyright 2004, Hyok S. Choi, for 2.6. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "proc-macros.S" + + + /* FIXME - this is also defined in cache-v4wb.S */ +#define CACHE_DSIZE 4096 /* 4K */ +#define CACHE_DLINESIZE 32 /* 8word */ +#define CACHE_DLIMIT (CACHE_DSIZE * 4) + +/* + * cpu_arm946_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm946_data_abort) + mrc p15, 0, r3, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r1, [r0] @ read aborted instruction + tst r1, r1, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm946_check_bugs() + */ +ENTRY(cpu_arm946_check_bugs) + mrs ip, cpsr + bic ip, ip, #PSR_F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm946_proc_init() + */ +ENTRY(cpu_arm946_proc_init) + mov pc, lr + +/* + * cpu_arm946_proc_fin() + */ +ENTRY(cpu_arm946_proc_fin) + stmfd sp!, {lr} + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, ip +#if defined(CONFIG_CPU_CACHE_V4WT) + bl v4wt_flush_kern_cache_all @ write-through +#elif defined(CONFIG_CPU_CACHE_V4WB) + bl v4wb_flush_kern_cache_all @ write-back +#endif /* CONFIG_CPU_CACHE_V4WT */ + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm946_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ +ENTRY(cpu_arm946_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * idle mode processing + */ +ENTRY(cpu_arm946_do_idle) +#if defined(CONFIG_CPU_ARM946_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* + * *FIXME* + */ +ENTRY(cpu_arm946_dcache_clean_area) +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #CACHE_DLINESIZE + subs r1, r1, #CACHE_DLINESIZE + bhi 1b + mov pc, lr +/* + * Function: arm946_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, + */ +ENTRY(cpu_arm946_switch_mm) + mov pc, lr + + + /* .section ".text.init", #alloc, #execinstr */ + __INIT + +__arm946_setup: + MRC p15, 0, R0, c1, c0, 0 @ get control register + +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + bic r0, r0, #0x000c @ W,D + bic r0, r0, #0x1000 @ I +/* + * Turn on what we want + */ +#ifdef CONFIG_CPU_MXU_ENABLE + orr r0, r0, #0x0001 @ Enable PU +#else + bic r0, r0, #0x0001 @ Disable PU +#endif + +#ifdef CONFIG_CPU_ARM940_D_CACHE_ON + orr r0, r0, #0x0004 @ Enable D cache +#endif +#ifdef CONFIG_CPU_ARM940_I_CACHE_ON + orr r0, r0, #0x1000 @ I Cache on +#endif + mov pc, lr + .size __arm946_setup, . - __arm946_setup + + __INITDATA + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm946_processor_functions, #object +ENTRY(arm946_processor_functions) + .word cpu_arm946_data_abort + .word cpu_arm946_proc_init + .word cpu_arm946_proc_fin + .word cpu_arm946_reset + .word cpu_arm946_do_idle + + .word cpu_arm946_dcache_clean_area + .word cpu_arm946_switch_mm + .size arm946_processor_functions, . - arm946_processor_functions + + .section ".rodata" + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_arm946_name, #object +cpu_arm946_name: + .ascii "ARM946E" + .size cpu_arm946_name, . - cpu_arm946_name + + .align + + + .section ".proc.info.init", #alloc, #execinstr + .type __arm946_proc_info,#object +__arm946_proc_info: + .long 0x41009460 + .long 0xff00fff0 + .long 0 + .long 0 + b __arm946_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm946_name + .long arm946_processor_functions + .long 0 + .long 0 +#if defined(CONFIG_CPU_CACHE_V4WT) + .long v4wt_cache_fns @ cache model +#elif defined(CONFIG_CPU_CACHE_V4WB) + .long v4wb_cache_fns @ cache model +#endif /* CONFIG_CPU_CACHE_V4WT */ + .size __arm946_proc_info, . - __arm946_proc_info + + diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S index 918ebf65..89185187 100644 --- a/arch/arm/mm/proc-arm9tdmi.S +++ b/arch/arm/mm/proc-arm9tdmi.S @@ -1,49 +1,191 @@ /* - * linux/arch/arm/mm/proc-arm9tdmi.S: utility functions for ARM9TDMI + * linux/arch/arm/mm/proc-arm9tdmi.S * - * Copyright (C) 2003-2006 Hyok S. Choi + * Copyright (C) 1997-2000 Russell King + * Copyright (C) 2003 Hyok S. Choi + * Copyright (C) 2004-2005 Tobias Lorenz * * 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. * + * for ARM9TDMI and the compatibles. */ #include #include #include -#include -#include #include #include #include +#include + +ENTRY(cpu_arm9tdmi_dcache_clean_area) + mov pc, lr - .text /* - * cpu_arm9tdmi_proc_init() - * cpu_arm9tdmi_do_idle() - * cpu_arm9tdmi_dcache_clean_area() - * cpu_arm9tdmi_switch_mm() + * Function: arm9tdmi_data_abort () * - * These are not required. + * Params : r2 = address of aborted instruction + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction + * + * Returns : r0 = address of abort + * : r1 = FSR */ -ENTRY(cpu_arm9tdmi_proc_init) -ENTRY(cpu_arm9tdmi_do_idle) -ENTRY(cpu_arm9tdmi_dcache_clean_area) -ENTRY(cpu_arm9tdmi_switch_mm) - mov pc, lr + +ENTRY(cpu_arm9tdmi_data_abort) + ldr r8, [r0] @ read arm instruction + tst r8, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + and r7, r8, #15 << 24 + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_unknown +/* 1 */ mov pc, lr @ swp +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r6 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? /* - * cpu_arm9tdmi_proc_fin() + * Function: arm9tdmi_proc_init (void) + * : arm9tdmi_proc_fin (void) + * + * Notes : This processor does not require these */ +ENTRY(cpu_arm9tdmi_proc_init) + mov pc, lr + ENTRY(cpu_arm9tdmi_proc_fin) mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, r0 mov pc, lr +ENTRY(cpu_arm9tdmi_do_idle) + mov pc, lr + /* - * Function: cpu_arm9tdmi_reset(loc) - * Params : loc(r0) address to jump to - * Purpose : Sets up everything for a reset and jump to the location for soft reset. + * Function: arm9tdmi_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, saving the old processes state, and restoring + * the new. + */ +ENTRY(cpu_arm9tdmi_switch_mm) + mov pc, lr + +/* + * Function: _arm9tdmi_reset + * Params : r0 = address to jump to + * Notes : This sets up everything for a reset */ ENTRY(cpu_arm9tdmi_reset) mov pc, r0 @@ -52,6 +194,7 @@ ENTRY(cpu_arm9tdmi_reset) .type __arm9tdmi_setup, #function __arm9tdmi_setup: + mov r0, #0x7c @ . .... .LDP WC.. mov pc, lr .size __arm9tdmi_setup, . - __arm9tdmi_setup @@ -63,26 +206,23 @@ __arm9tdmi_setup: */ .type arm9tdmi_processor_functions, #object ENTRY(arm9tdmi_processor_functions) - .word nommu_early_abort + .word cpu_arm9tdmi_data_abort .word cpu_arm9tdmi_proc_init .word cpu_arm9tdmi_proc_fin .word cpu_arm9tdmi_reset .word cpu_arm9tdmi_do_idle .word cpu_arm9tdmi_dcache_clean_area .word cpu_arm9tdmi_switch_mm - .word 0 @ cpu_*_set_pte .size arm9tdmi_processor_functions, . - arm9tdmi_processor_functions .section ".rodata" .type cpu_arch_name, #object -cpu_arch_name: - .asciz "armv4t" +cpu_arch_name: .asciz "armv4t" .size cpu_arch_name, . - cpu_arch_name .type cpu_elf_name, #object -cpu_elf_name: - .asciz "v4" +cpu_elf_name: .asciz "v4" .size cpu_elf_name, . - cpu_elf_name .type cpu_arm9tdmi_name, #object @@ -99,29 +239,12 @@ cpu_p2001_name: .section ".proc.info.init", #alloc, #execinstr - .type __arm9tdmi_proc_info, #object -__arm9tdmi_proc_info: - .long 0x41009900 - .long 0xfff8ff00 - .long 0 - .long 0 - b __arm9tdmi_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT - .long cpu_arm9tdmi_name - .long arm9tdmi_processor_functions - .long 0 - .long 0 - .long v4_cache_fns - .size __arm9tdmi_proc_info, . - __arm9dmi_proc_info - .type __p2001_proc_info, #object __p2001_proc_info: .long 0x41029000 .long 0xffffffff - .long 0 - .long 0 + .long 0x00000c1e + .long 0x00000c1e b __arm9tdmi_setup .long cpu_arch_name .long cpu_elf_name diff --git a/arch/arm/mm/proc-lpc22xx.S b/arch/arm/mm/proc-lpc22xx.S new file mode 100644 index 00000000..115a763e --- /dev/null +++ b/arch/arm/mm/proc-lpc22xx.S @@ -0,0 +1,291 @@ +/* + * linux/arch/armnommu/mm/proc-lpc22xx.S + * + * Copyright (C) 1997-2000 Russell King + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * Modified for lpc22xx cache + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +ENTRY(lpc22xx_flush_user_cache_all) +ENTRY(lpc22xx_flush_kern_cache_all) +ENTRY(lpc22xx_flush_user_cache_range) +ENTRY(lpc22xx_coherent_kern_range) +ENTRY(lpc22xx_coherent_user_range) +ENTRY(lpc22xx_flush_kern_dcache_page) +ENTRY(lpc22xx_dma_inv_range) +ENTRY(lpc22xx_dma_flush_range) +ENTRY(lpc22xx_dma_clean_range) + mov pc, lr + +ENTRY(cpu_arm7_dcache_clean_area) + mov pc, lr + +/* + * Function: arm6_7_data_abort () + * + * Params : r2 = address of aborted instruction + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction + * + * Returns : r0 = address of abort + * : r1 = FSR + */ + +ENTRY(cpu_arm7_data_abort) +@FIXME + ldr r8, [r2] @ read arm instruction + tst r8, #1 << 20 @ L = 1 -> write? + and r7, r8, #15 << 24 + orr r1, r7, #1 + orreq r1, r1, #1 << 8 @ yes. + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_unknown +/* 1 */ mov pc, lr @ swp +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + +ENTRY(cpu_arm6_data_abort) +@FIXME + ldr r8, [r2] @ read arm instruction + tst r8, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + and r7, r8, #14 << 24 + teq r7, #8 << 24 @ was it ldm/stm + movne pc, lr + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r6 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? + +/* + * Function: arm6_7_proc_init (void) + * : arm6_7_proc_fin (void) + * + * Notes : This processor does not require these + */ +ENTRY(cpu_arm7_proc_init) + mov pc, lr + +ENTRY(cpu_arm7_proc_fin) + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, r0 + mov pc, lr + +ENTRY(cpu_arm7_do_idle) + mov r0, #-EINVAL + mov pc, lr + +/* + * Function: arm6_7_switch_mm(unsigned long pgd_phys) + * Params : pgd_phys Physical address of page table + * Purpose : Perform a task switch, saving the old processes state, and restoring + * the new. + */ +ENTRY(cpu_arm7_switch_mm) + mov pc, lr + +/* + * Function: _arm6_7_reset + * Params : r0 = address to jump to + * Notes : This sets up everything for a reset + */ +ENTRY(cpu_arm7_reset) + mov pc, r0 + + + __INIT + + .type __arm7_setup, #function +__arm7_setup: + mov pc, lr + .size __arm7_setup, . - __arm7_setup + + __INITDATA + + .type lpc22xx_cache_fns, #object +ENTRY(lpc22xx_cache_fns) + .long lpc22xx_flush_kern_cache_all + .long lpc22xx_flush_user_cache_all + .long lpc22xx_flush_user_cache_range + .long lpc22xx_coherent_kern_range + .long lpc22xx_coherent_user_range + .long lpc22xx_flush_kern_dcache_page + .long lpc22xx_dma_inv_range + .long lpc22xx_dma_clean_range + .long lpc22xx_dma_flush_range + .size lpc22xx_cache_fns, . - lpc22xx_cache_fns + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm7_processor_functions, #object +ENTRY(arm7_processor_functions) + .word cpu_arm7_data_abort + .word cpu_arm7_proc_init + .word cpu_arm7_proc_fin + .word cpu_arm7_reset + .word cpu_arm7_do_idle + .word cpu_arm7_dcache_clean_area + .word cpu_arm7_switch_mm + .size arm7_processor_functions, . - arm7_processor_functions + + .section ".rodata" + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_lpc22xx, #object +cpu_lpc22xx_name: + .asciz "Philips-LPC22xx" + .size cpu_lpc22xx_name, . - cpu_lpc22xx_name + + .align + + .section ".proc.info.init", #alloc, #execinstr + + .type __lpc22xx_proc_info, #object +__lpc22xx_proc_info: + .long 0x22000000 + .long 0xffff0000 + .long 0 + .long 0 + b __arm7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_lpc22xx_name + .long arm7_processor_functions + .long 0 + .long 0 + .long lpc22xx_cache_fns + .size __lpc22xx_proc_info, . - __lpc22xx_proc_info + diff --git a/arch/arm/mm/proc-s3c4510b.S b/arch/arm/mm/proc-s3c4510b.S new file mode 100644 index 00000000..38a5b842 --- /dev/null +++ b/arch/arm/mm/proc-s3c4510b.S @@ -0,0 +1,387 @@ +/* + * linux/arch/armnommu/mm/proc-s3c4510b.S + * + * Copyright (C) 1997-2000 Russell King + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * Modified for s3c4510b cache + * Copyright (c) 2005 Hyok S. Choi + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * flush_user_cache_all() + * + * Invalidate all cache entries in a particular address + * space. + * + * - mm - mm_struct describing address space + */ +ENTRY(s3c4510b_flush_user_cache_all) + /* FALLTHROUGH */ +/* + * flush_kern_cache_all() + * + * Clean and invalidate the entire cache. + */ +ENTRY(s3c4510b_flush_kern_cache_all) + /* FALLTHROUGH */ + +/* + * flush_user_cache_range(start, end, flags) + * + * Invalidate a range of cache entries in the specified + * address space. + * + * - start - start address (may not be aligned) + * - end - end address (exclusive, may not be aligned) + * - flags - vma_area_struct flags describing address space + */ +ENTRY(s3c4510b_flush_user_cache_range) + stmfd sp!, {r5-r8, lr} + /* save current cache state */ + ldr r7, =REG_SYSCFG + ldr r8, [r7] + /* disable cache */ + ldr r6, =0x83ffffa0 + str r6, [r7] + /* zero out the 1KB TAG RAM area starting @ 0x11000000 */ + ldr r7, =0x11000000 + ldr r6, =(0x11000000 + 1024) + ldr r5, =0x0 +tag_zero: + str r5, [r7] + add r7, r7, #4 + cmp r6, r7 + bne tag_zero + + /* restore previoux cache state */ + ldr r7, =REG_SYSCFG + str r8, [r7] + + ldmfd sp!, {r5-r8, pc} + +/* + * coherent_kern_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(s3c4510b_coherent_kern_range) + /* FALLTHROUGH */ + + +/* + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(s3c4510b_coherent_user_range) + +/* + * flush_kern_dcache_page(void *page) + * + * Ensure no D cache aliasing occurs, either with itself or + * the I cache + * + * - addr - page aligned address + */ +ENTRY(s3c4510b_flush_kern_dcache_page) + /* FALLTHROUGH */ + +/* + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(s3c4510b_dma_inv_range) + /* FALLTHROUGH */ + +/* + * dma_flush_range(start, end) + * + * Clean and invalidate the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(s3c4510b_dma_flush_range) + /* FALLTHROUGH */ + +/* + * dma_clean_range(start, end) + * + * Clean (write back) the specified virtual address range. + * + * - start - virtual start address + * - end - virtual end address + */ +ENTRY(s3c4510b_dma_clean_range) + /* FALLTHROUGH */ + +ENTRY(cpu_s3c4510b_dcache_clean_area) + mov pc, lr + +/* + * Function: cpu_s3c4510b_data_abort () + * + * Params : r2 = address of aborted instruction + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction + * + * Returns : r0 = address of abort + * : r1 = FSR + */ + +ENTRY(cpu_s3c4510b_data_abort) +@FIXME + ldr r8, [r2] @ read arm instruction + tst r8, #1 << 20 @ L = 1 -> write? + and r7, r8, #15 << 24 + orr r1, r7, #1 + orreq r1, r1, #1 << 8 @ yes. + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_unknown +/* 1 */ mov pc, lr @ swp +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r6 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? + + +ENTRY(cpu_s3c4510b_proc_init) + mov pc, lr + +ENTRY(cpu_s3c4510b_proc_fin) + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, r0 + mov r0, #0 + mov pc, lr + +ENTRY(cpu_s3c4510b_do_idle) + mov r0, #-EINVAL + mov pc, lr + +ENTRY(cpu_s3c4510b_switch_mm) + mov pc, lr + +ENTRY(cpu_s3c4510b_reset) + mov r1, #0 + mov pc, r0 + + + __INIT + + .type __s3c4510b_setup, #function +__s3c4510b_setup: + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, r0 + mov r0, #0 + mov pc, lr + .size __s3c4510b_setup, . - __s3c4510b_setup + + __INITDATA + + .type s3c4510b_cache_fns, #object +ENTRY(s3c4510b_cache_fns) + .long s3c4510b_flush_kern_cache_all + .long s3c4510b_flush_user_cache_all + .long s3c4510b_flush_user_cache_range + .long s3c4510b_coherent_kern_range + .long s3c4510b_coherent_user_range + .long s3c4510b_flush_kern_dcache_page + .long s3c4510b_dma_inv_range + .long s3c4510b_dma_clean_range + .long s3c4510b_dma_flush_range + .size s3c4510b_cache_fns, . - s3c4510b_cache_fns + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type s3c4510b_processor_functions, #object +ENTRY(s3c4510b_processor_functions) + .word cpu_s3c4510b_data_abort + .word cpu_s3c4510b_proc_init + .word cpu_s3c4510b_proc_fin + .word cpu_s3c4510b_reset + .word cpu_s3c4510b_do_idle + .word cpu_s3c4510b_dcache_clean_area + .word cpu_s3c4510b_switch_mm + .size s3c4510b_processor_functions, . - s3c4510b_processor_functions + + .section ".rodata" + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4t" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + + .type cpu_s3c4510b, #object +cpu_s3c4510b_name: + .asciz "Samsung-S3C4510B" + .size cpu_s3c4510b_name, . - cpu_s3c4510b_name + + .align + + .section ".proc.info.init", #alloc, #execinstr + + .type __s3c4510b_proc_info, #object +__s3c4510b_proc_info: + .long 0x36807000 + .long 0xfffff000 + .long 0 + .long 0 + b __s3c4510b_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_s3c4510b_name + .long s3c4510b_processor_functions + .long 0 + .long 0 + .long s3c4510b_cache_fns + .size __s3c4510b_proc_info, . - __s3c4510b_proc_info + diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index ab143557..e4160002 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -2,6 +2,7 @@ * linux/arch/arm/mm/proc-syms.c * * Copyright (C) 2000-2002 Russell King + * Modified by Hyok S. Choi, 2004 * * 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 @@ -17,7 +18,9 @@ #ifndef MULTI_CPU EXPORT_SYMBOL(cpu_dcache_clean_area); +#ifdef CONFIG_MMU EXPORT_SYMBOL(cpu_set_pte); +#endif #else EXPORT_SYMBOL(processor); #endif @@ -31,12 +34,14 @@ EXPORT_SYMBOL(__cpuc_coherent_kern_range); EXPORT_SYMBOL(cpu_cache); #endif +#if 0 // mask by Victor Yu. 02-07-2007 #ifndef MULTI_USER EXPORT_SYMBOL(__cpu_clear_user_page); EXPORT_SYMBOL(__cpu_copy_user_page); #else EXPORT_SYMBOL(cpu_user); #endif +#endif /* * No module should need to touch the TLB (and currently diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 4ace2d80..4f0d9361 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -35,6 +35,9 @@ #include #include "proc-macros.S" +#ifndef CONFIG_MMU +#error "need to be revisited" +#endif /* * This is the maximum size of an area which will be flushed. If the * area is larger than this, then we flush the whole cache. diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 2749c1f8..e5823a61 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -30,6 +30,9 @@ #include #include "proc-macros.S" +#ifndef CONFIG_MMU +#error "need to be revisited" +#endif /* * This is the maximum size of an area which will be flushed. If the area * is larger than this, then we flush the whole cache diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 579c69ae..751e7dd2 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -255,7 +255,7 @@ mport3 ARCH_MPORT3 MPORT3 237 pxa_eagle250 ARCH_PXA_EAGLE250 PXA_EAGLE250 238 pdb ARCH_PDB PDB 239 blue_2g SA1100_BLUE_2G BLUE_2G 240 -bluearch SA1100_BLUEARCH BLUEARCH 241 +moxart MOXART MOXART 241 ixdp2400 ARCH_IXDP2400 IXDP2400 242 ixdp2800 ARCH_IXDP2800 IXDP2800 243 explorer SA1100_EXPLORER EXPLORER 244 @@ -525,7 +525,7 @@ scb9328 MACH_SCB9328 SCB9328 508 omap_h3 MACH_OMAP_H3 OMAP_H3 509 omap_h4 MACH_OMAP_H4 OMAP_H4 510 n10 MACH_N10 N10 511 -montejade MACH_MONTAJADE MONTAJADE 512 +montejade MACH_MONTEJADE MONTEJADE 512 sg560 MACH_SG560 SG560 513 dp1000 MACH_DP1000 DP1000 514 omap_osk MACH_OMAP_OSK OMAP_OSK 515 diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S index 011b7a49..8a084e67 100644 --- a/arch/i386/boot/bootsect.S +++ b/arch/i386/boot/bootsect.S @@ -4,13 +4,29 @@ * modified by Drew Eckhardt * modified by Bruce Evans (bde) * modified by Chris Noe (May 1999) (as86 -> gas) - * gutted by H. Peter Anvin (Jan 2003) + * + * 360k/720k disk support: Andrzej Krzysztofowicz * * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment * addresses must be multiplied by 16 to obtain their respective linear * addresses. To avoid confusion, linear addresses are written using leading * hex while segment addresses are written as segment:offset. * + * bde - should not jump blindly, there may be systems with only 512K low + * memory. Use int 0x12 to get the top of memory, etc. + * + * It then loads 'setup' directly after itself (0x90200), and the system + * at 0x10000, using BIOS interrupts. + * + * NOTE! currently system is at most (8*65536-4096) bytes long. This should + * be no problem, even in the future. I want to keep it simple. This 508 kB + * kernel size should be enough, especially as this doesn't contain the + * buffer cache as in minix (and especially now that the kernel is + * compressed :-) + * + * The loader has been made as simple as possible, and continuous + * read errors will result in a unbreakable loop. Reboot by hand. It + * loads pretty fast by getting whole tracks at a time whenever possible. */ #include @@ -43,51 +59,362 @@ SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ .global _start _start: - # Normalize the start address - jmpl $BOOTSEG, $start2 +# First things first. Move ourself from 0x7C00 -> 0x90000 and jump there. -start2: - movw %cs, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw $0x7c00, %sp - sti + movw $BOOTSEG, %ax + movw %ax, %ds # %ds = BOOTSEG + movw $INITSEG, %ax + movw %ax, %es # %ax = %es = INITSEG + movw $256, %cx + subw %si, %si + subw %di, %di cld + rep + movsw + ljmp $INITSEG, $go + +# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We +# wouldn't have to worry about this if we checked the top of memory. Also +# my BIOS can be configured to put the wini drive tables in high memory +# instead of in the vector table. The old stack might have clobbered the +# drive table. - movw $bugger_off_msg, %si +go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >= + # length of bootsect + length of + # setup + room for stack; + # 12 is disk parm size. + movw %ax, %ds # %ax and %es already contain INITSEG + movw %ax, %ss + movw %di, %sp # put stack at INITSEG:0x4000-12. + +# Many BIOS's default disk parameter tables will not recognize +# multi-sector reads beyond the maximum sector number specified +# in the default diskette parameter tables - this may mean 7 +# sectors in some cases. +# +# Since single sector reads are slow and out of the question, +# we must take care of this by creating new parameter tables +# (for the first disk) in RAM. We will set the maximum sector +# count to 36 - the most we will encounter on an ED 2.88. +# +# High doesn't hurt. Low does. +# +# Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0, +# and %gs is unused. + + movw %cx, %fs # %fs = 0 + movw $0x78, %bx # %fs:%bx is parameter table address + pushw %ds + ldsw %fs:(%bx), %si # %ds:%si is source + movb $6, %cl # copy 12 bytes + pushw %di # %di = 0x4000-12. + rep # don't worry about cld + movsw # already done above + popw %di + popw %ds + movb $36, 0x4(%di) # patch sector count + movw %di, %fs:(%bx) + movw %es, %fs:2(%bx) + +# Get disk drive parameters, specifically number of sectors/track. -msg_loop: +# It seems that there is no BIOS call to get the number of sectors. +# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18 +# can be read, 15 if sector 15 can be read. Otherwise guess 9. +# Note that %cx = 0 from rep movsw above. + + movw $disksizes, %si # table of sizes to try +probe_loop: lodsb - andb %al, %al - jz die - movb $0xe, %ah - movw $7, %bx + cbtw # extend to word + movw %ax, sectors + cmpw $disksizes+4, %si + jae got_sectors # If all else fails, try 9 + + xchgw %cx, %ax # %cx = track and sector + xorw %dx, %dx # drive 0, head 0 + movw $0x0200, %bx # address = 512, in INITSEG (%es = %cs) + movw $0x0201, %ax # service 2, 1 sector + int $0x13 + jc probe_loop # try next value + +got_sectors: + movb $0x03, %ah # read cursor pos + xorb %bh, %bh int $0x10 - jmp msg_loop + movw $9, %cx + movb $0x07, %bl # page 0, attribute 7 (normal) + # %bh is set above; int10 doesn't + # modify it + movw $msg1, %bp + movw $0x1301, %ax # write string, move cursor + int $0x10 # tell the user we're loading.. + +# Load the setup-sectors directly after the moved bootblock (at 0x90200). +# We should know the drive geometry to do it, as setup may exceed first +# cylinder (for 9-sector 360K and 720K floppies). + + movw $0x0001, %ax # set sread (sector-to-read) to 1 as + movw $sread, %si # the boot sector has already been read + movw %ax, (%si) + + xorw %ax, %ax # reset FDC + xorb %dl, %dl + int $0x13 + movw $0x0200, %bx # address = 512, in INITSEG +next_step: + movb setup_sects, %al + movw sectors, %cx + subw (%si), %cx # (%si) = sread + cmpb %cl, %al + jbe no_cyl_crossing + movw sectors, %ax + subw (%si), %ax # (%si) = sread +no_cyl_crossing: + call read_track + pushw %ax # save it + call set_next # set %bx properly; it uses %ax,%cx,%dx + popw %ax # restore + subb %al, setup_sects # rest - for next step + jnz next_step + + pushw $SYSSEG + popw %es # %es = SYSSEG + call read_it + call kill_motor + call print_nl + +# After that we check which root-device to use. If the device is +# defined (!= 0), nothing is done and the given device is used. +# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8) +# depending on the number of sectors we pretend to know we have. + +# Segments are as follows: %cs = %ds = %ss = INITSEG, +# %es = SYSSEG, %fs = 0, %gs is unused. + + movw root_dev, %ax + orw %ax, %ax + jne root_defined + + movw sectors, %bx + movw $0x0208, %ax # /dev/ps0 - 1.2Mb + cmpw $15, %bx + je root_defined + + movb $0x1c, %al # /dev/PS0 - 1.44Mb + cmpw $18, %bx + je root_defined + + movb $0x20, %al # /dev/fd0H2880 - 2.88Mb + cmpw $36, %bx + je root_defined + + movb $0, %al # /dev/fd0 - autodetect +root_defined: + movw %ax, root_dev + +# After that (everything loaded), we jump to the setup-routine +# loaded directly after the bootblock: + + ljmp $SETUPSEG, $0 + +# These variables are addressed via %si register as it gives shorter code. + +sread: .word 0 # sectors read of current track +head: .word 0 # current head +track: .word 0 # current track + +# This routine loads the system at address SYSSEG, making sure +# no 64kB boundaries are crossed. We try to load it as fast as +# possible, loading whole tracks whenever we can. + +read_it: + movw %es, %ax # %es = SYSSEG when called + testw $0x0fff, %ax +die: jne die # %es must be at 64kB boundary + xorw %bx, %bx # %bx is starting address within segment +rp_read: +#ifdef __BIG_KERNEL__ + # look in setup.S for bootsect_kludge + bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the + lcall bootsect_kludge # bootsector + bootsect_kludge offset +#else + movw %es, %ax + subw $SYSSEG, %ax + movw %bx, %cx + shr $4, %cx + add %cx, %ax # check offset +#endif + cmpw syssize, %ax # have we loaded everything yet? + jbe ok1_read + + ret + +ok1_read: + movw sectors, %ax + subw (%si), %ax # (%si) = sread + movw %ax, %cx + shlw $9, %cx + addw %bx, %cx + jnc ok2_read + + je ok2_read -die: - # Allow the user to press a key, then reboot xorw %ax, %ax - int $0x16 - int $0x19 + subw %bx, %ax + shrw $9, %ax +ok2_read: + call read_track + call set_next + jmp rp_read + +read_track: + pusha + pusha + movw $0xe2e, %ax # loading... message 2e = . + movw $7, %bx + int $0x10 + popa - # int 0x19 should never return. In case it does anyway, - # invoke the BIOS reset code... - ljmp $0xf000,$0xfff0 +# Accessing head, track, sread via %si gives shorter code. + movw 4(%si), %dx # 4(%si) = track + movw (%si), %cx # (%si) = sread + incw %cx + movb %dl, %ch + movw 2(%si), %dx # 2(%si) = head + movb %dl, %dh + andw $0x0100, %dx + movb $2, %ah + pushw %dx # save for error dump + pushw %cx + pushw %bx + pushw %ax + int $0x13 + jc bad_rt -bugger_off_msg: - .ascii "Direct booting from floppy is no longer supported.\r\n" - .ascii "Please use a boot loader program instead.\r\n" - .ascii "\n" - .ascii "Remove disk and press any key to reboot . . .\r\n" - .byte 0 + addw $8, %sp + popa + ret + +set_next: + movw %ax, %cx + addw (%si), %ax # (%si) = sread + cmp sectors, %ax + jne ok3_set + movw $0x0001, %ax + xorw %ax, 2(%si) # change head + jne ok4_set + incw 4(%si) # next track +ok4_set: + xorw %ax, %ax +ok3_set: + movw %ax, (%si) # set sread + shlw $9, %cx + addw %cx, %bx + jnc set_next_fin + movw %es, %ax + addb $0x10, %ah + movw %ax, %es + xorw %bx, %bx +set_next_fin: + ret + +bad_rt: + pushw %ax # save error code + call print_all # %ah = error, %al = read + xorb %ah, %ah + xorb %dl, %dl + int $0x13 + addw $10, %sp + popa + jmp read_track + +# print_all is for debugging purposes. +# +# it will print out all of the registers. The assumption is that this is +# called from a routine, with a stack frame like +# +# %dx +# %cx +# %bx +# %ax +# (error) +# ret <- %sp + +print_all: + movw $5, %cx # error code + 4 registers + movw %sp, %bp +print_loop: + pushw %cx # save count remaining + call print_nl # <-- for readability + cmpb $5, %cl + jae no_reg # see if register name is needed + + movw $0xe05 + 'A' - 1, %ax + subb %cl, %al + int $0x10 + movb $'X', %al + int $0x10 + movb $':', %al + int $0x10 +no_reg: + addw $2, %bp # next register + call print_hex # print it + popw %cx + loop print_loop + ret + +print_nl: + movw $0xe0d, %ax # CR + int $0x10 + movb $0xa, %al # LF + int $0x10 + ret + +# print_hex is for debugging purposes, and prints the word +# pointed to by %ss:%bp in hexadecimal. + +print_hex: + movw $4, %cx # 4 hex digits + movw (%bp), %dx # load word into %dx +print_digit: + rolw $4, %dx # rotate to use low 4 bits + movw $0xe0f, %ax # %ah = request + andb %dl, %al # %al = mask for nybble + addb $0x90, %al # convert %al to ascii hex + daa # in only four instructions! + adc $0x40, %al + daa + int $0x10 + loop print_digit + ret + +# This procedure turns off the floppy drive motor, so +# that we enter the kernel in a known state, and +# don't have to worry about it later. +# NOTE: Doesn't save %ax or %dx; do it yourself if you need to. + +kill_motor: +#if 1 + xorw %ax, %ax # reset FDC + xorb %dl, %dl + int $0x13 +#else + movw $0x3f2, %dx + xorb %al, %al + outb %al, %dx +#endif + ret +sectors: .word 0 +disksizes: .byte 36, 18, 15, 9 +msg1: .byte 13, 10 + .ascii "Loading" - # Kernel attributes; used by setup +# XXX: This is a fairly snug fit. - .org 497 +.org 497 setup_sects: .byte SETUPSECTS root_flags: .word ROOT_RDONLY syssize: .word SYSSIZE diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S index b5893e4e..86e9f4b7 100644 --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S @@ -27,6 +27,12 @@ #include #include +#undef __BOOT_CS +#define __BOOT_CS 0x10 +#undef __BOOT_DS +#define __BOOT_DS 0x18 + + .globl startup_32 startup_32: diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index b2ccd543..1636ac48 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -15,6 +15,11 @@ #include #include +#undef __BOOT_CS +#define __BOOT_CS 0x10 +#undef __BOOT_DS +#define __BOOT_DS 0x18 + /* * gzip declarations */ diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 3aec4538..9677d809 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -44,6 +44,13 @@ * * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes * by Robert Schwebel, December 2001 + * + * BIOS Enhanced Disk Drive support + * by Matt Domsch October 2002 + * conformant to T13 Committee www.t13.org + * projects 1572D, 1484D, 1386D, 1226DT + * disk signature read by Matt Domsch + * and Andrew Wilks September 2003 */ #include @@ -51,7 +58,16 @@ #include #include #include +#include #include + +#undef __BOOT_CS +#define __BOOT_CS 0x10 +#undef __BOOT_DS +#define __BOOT_DS 0x18 +#undef __KERNEL_CS +#define __KERNEL_CS 0x10 +#define __MAXMEM (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff /* Signature words to ensure LILO loaded us right */ #define SIG1 0xAA55 @@ -132,7 +148,7 @@ ramdisk_image: .long 0 # address of loaded ramdisk image ramdisk_size: .long 0 # its size in bytes bootsect_kludge: - .long 0 # obsolete + .word bootsect_helper, SETUPSEG heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) # space from here (exclusive) down to @@ -155,15 +171,12 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff - # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd trampoline: call start_of_setup - .align 16 - # The offset at this point is 0x240 - .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff) + .space 1024 # End of setup header ##################################################### start_of_setup: @@ -209,7 +222,7 @@ prtspc: movb $0x20, %al # Print single space (note: fall-thru) # Part of above routine, this one just prints ascii al prtchr: pushw %ax pushw %cx - movw $7,%bx + xorb %bh, %bh movw $0x01, %cx movb $0x0e, %ah int $0x10 @@ -303,7 +316,7 @@ loader_ok: # a whole bunch of different types, and allows memory holes and # everything. We scan through this memory map and build a list # of the first 32 memory areas, which we return at [E820MAP]. -# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification. +# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm #define SMAP 0x534d4150 @@ -332,9 +345,9 @@ jmpe820: # sizeof(e820rec). # good820: - movb (E820NR), %al # up to 128 entries + movb (E820NR), %al # up to 32 entries cmpb $E820MAX, %al - jae bail820 + jnl bail820 incb (E820NR) movw %di, %ax @@ -472,24 +485,6 @@ sysdesc_ok: movsb popw %ds no_mca: -#ifdef CONFIG_X86_VOYAGER - movb $0xff, 0x40 # flag on config found - movb $0xc0, %al - mov $0xff, %ah - int $0x15 # put voyager config info at es:di - jc no_voyager - movw $0x40, %si # place voyager info in apm table - cld - movw $7, %cx -voyager_rep: - movb %es:(%di), %al - movb %al,(%si) - incw %di - incw %si - decw %cx - jnz voyager_rep -no_voyager: -#endif # Check for PS/2 pointing device movw %cs, %ax # aka SETUPSEG subw $DELTA_INITSEG, %ax # aka INITSEG @@ -502,17 +497,6 @@ no_voyager: movb $0xAA, (0x1ff) # device present no_psmouse: -#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) - movl $0x0000E980, %eax # IST Support - movl $0x47534943, %edx # Request value - int $0x15 - - movl %eax, (96) - movl %ebx, (100) - movl %ecx, (104) - movl %edx, (108) -#endif - #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) # Then check for an APM BIOS... # %ds points to the bootsector @@ -573,13 +557,94 @@ no_32_apm_bios: done_apm_bios: #endif -#include "edd.S" +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) +# Read the first sector of device 80h and store the 4-byte signature + movl $0xFFFFFFFF, %eax + movl %eax, (DISK80_SIG_BUFFER) # assume failure + movb $READ_SECTORS, %ah + movb $1, %al # read 1 sector + movb $0x80, %dl # from device 80 + movb $0, %dh # at head 0 + movw $1, %cx # cylinder 0, sector 0 + pushw %es + pushw %ds + popw %es + movw $EDDBUF, %bx + int $0x13 + jc disk_sig_done + movl (EDDBUF+MBR_SIG_OFFSET), %eax + movl %eax, (DISK80_SIG_BUFFER) # store success +disk_sig_done: + popw %es + +# Do the BIOS Enhanced Disk Drive calls +# This consists of two calls: +# int 13h ah=41h "Check Extensions Present" +# int 13h ah=48h "Get Device Parameters" +# +# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use +# in the empty_zero_page at EDDBUF. The first four bytes of which are +# used to store the device number, interface support map and version +# results from fn41. The following 74 bytes are used to store +# the results from fn48. Starting from device 80h, fn41, then fn48 +# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). +# Then the pointer is incremented to store the data for the next call. +# This repeats until either a device doesn't exist, or until EDDMAXNR +# devices have been stored. +# The one tricky part is that ds:si always points four bytes into +# the structure, and the fn41 results are stored at offsets +# from there. This removes the need to increment the pointer for +# every store, and leaves it ready for the fn48 call. +# A second one-byte buffer, EDDNR, in the empty_zero_page stores +# the number of BIOS devices which exist, up to EDDMAXNR. +# In setup.c, copy_edd() stores both empty_zero_page buffers away +# for later use, as they would get overwritten otherwise. +# This code is sensitive to the size of the structs in edd.h +edd_start: + # %ds points to the bootsector + # result buffer for fn48 + movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results + # kept just before that + movb $0, (EDDNR) # zero value at EDDNR + movb $0x80, %dl # BIOS device 0x80 + +edd_check_ext: + movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 + movw $EDDMAGIC1, %bx # magic + int $0x13 # make the call + jc edd_done # no more BIOS devices + + cmpw $EDDMAGIC2, %bx # is magic right? + jne edd_next # nope, next... + + movb %dl, %ds:-4(%si) # store device number + movb %ah, %ds:-3(%si) # store version + movw %cx, %ds:-2(%si) # store extensions + incb (EDDNR) # note that we stored something + +edd_get_device_params: + movw $EDDPARMSIZE, %ds:(%si) # put size + movb $GETDEVICEPARAMETERS, %ah # Function 48 + int $0x13 # make the call + # Don't check for fail return + # it doesn't matter. + movw %si, %ax # increment si + addw $EDDPARMSIZE+EDDEXTSIZE, %ax + movw %ax, %si + +edd_next: + incb %dl # increment to next device + cmpb $EDDMAXNR, (EDDNR) # Out of space? + jb edd_check_ext # keep looping + +edd_done: +#endif # Now we want to move to protected mode ... cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - lcall *%cs:realmode_swtch + lcall %cs:realmode_swtch jmp rmodeswtch_end @@ -689,12 +754,12 @@ end_move_self: # now we are at the right place # AMD Elan bug fix by Robert Schwebel. # -#if defined(CONFIG_X86_ELAN) +#if defined(CONFIG_MELAN) movb $0x02, %al # alternate A20 gate outb %al, $0x92 # this works on SC410/SC520 a20_elan_wait: - call a20_test - jz a20_elan_wait + call a20_test + jz a20_elan_wait jmp a20_done #endif @@ -703,7 +768,6 @@ A20_TEST_LOOPS = 32 # Iterations per wait A20_ENABLE_LOOPS = 255 # Total loops to try -#ifndef CONFIG_X86_VOYAGER a20_try_loop: # First, see if we are on a system with no A20 gate. @@ -722,14 +786,11 @@ a20_bios: jnz a20_done # Try enabling A20 through the keyboard controller -#endif /* CONFIG_X86_VOYAGER */ a20_kbc: call empty_8042 -#ifndef CONFIG_X86_VOYAGER call a20_test # Just in case the BIOS worked jnz a20_done # but had a delayed reaction. -#endif movb $0xD1, %al # command write outb %al, $0x64 @@ -739,7 +800,6 @@ a20_kbc: outb %al, $0x60 call empty_8042 -#ifndef CONFIG_X86_VOYAGER # Wait until a20 really *is* enabled; it can take a fair amount of # time on certain systems; Toshiba Tecras are known to have this # problem. @@ -787,7 +847,6 @@ a20_err_msg: # If we get here, all is good a20_done: -#endif /* CONFIG_X86_VOYAGER */ # set up gdt and idt lidt idt_48 # load idt with 0,0 xorl %eax, %eax # Compute gdt_base @@ -838,11 +897,8 @@ flush_instr: movw %cs, %si subw $DELTA_INITSEG, %si shll $4, %esi # Convert to 32-bit pointer - -# jump to startup_32 in arch/i386/boot/compressed/head.S -# # NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__BOOT_CS +# jmpi 0x100000,__KERNEL_CS # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit. @@ -853,7 +909,7 @@ flush_instr: .byte 0x66, 0xea # prefix + jmpi-opcode code32: .long 0x1000 # will be set to 0x100000 # for big kernels - .word __BOOT_CS + .word __KERNEL_CS # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE @@ -874,8 +930,89 @@ default_switch: outb %al, $0x70 lret +# This routine only gets called, if we get loaded by the simple +# bootsect loader _and_ have a bzImage to load. +# Because there is no place left in the 512 bytes of the boot sector, +# we must emigrate to code space here. +bootsect_helper: + cmpw $0, %cs:bootsect_es + jnz bootsect_second + + movb $0x20, %cs:type_of_loader + movw %es, %ax + shrw $4, %ax + movb %ah, %cs:bootsect_src_base+2 + movw %es, %ax + movw %ax, %cs:bootsect_es + subw $SYSSEG, %ax + lret # nothing else to do for now + +bootsect_second: + pushw %cx + pushw %si + pushw %bx + testw %bx, %bx # 64K full? + jne bootsect_ex + + movw $0x8000, %cx # full 64K, INT15 moves words + pushw %cs + popw %es + movw $bootsect_gdt, %si + movw $0x8700, %ax + int $0x15 + jc bootsect_panic # this, if INT15 fails + + movw %cs:bootsect_es, %es # we reset %es to always point + incb %cs:bootsect_dst_base+2 # to 0x10000 +bootsect_ex: + movb %cs:bootsect_dst_base+2, %ah + shlb $4, %ah # we now have the number of + # moved frames in %ax + xorb %al, %al + popw %bx + popw %si + popw %cx + lret + +bootsect_gdt: + .word 0, 0, 0, 0 + .word 0, 0, 0, 0 + +bootsect_src: + .word 0xffff + +bootsect_src_base: + .byte 0x00, 0x00, 0x01 # base = 0x010000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + +bootsect_dst: + .word 0xffff + +bootsect_dst_base: + .byte 0x00, 0x00, 0x10 # base = 0x100000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + .word 0, 0, 0, 0 # BIOS CS + .word 0, 0, 0, 0 # BIOS DS + +bootsect_es: + .word 0 + +bootsect_panic: + pushw %cs + popw %ds + cld + leaw bootsect_panic_mess, %si + call prtstr + +bootsect_panic_loop: + jmp bootsect_panic_loop + +bootsect_panic_mess: + .string "INT15 refuses to access high mem, giving up." + -#ifndef CONFIG_X86_VOYAGER # This routine tests whether or not A20 is enabled. If so, it # exits with zf = 0. # @@ -906,8 +1043,6 @@ a20_test_wait: popw %cx ret -#endif /* CONFIG_X86_VOYAGER */ - # This routine checks that the keyboard command queue is empty # (after emptying the output buffers) # @@ -967,20 +1102,9 @@ delay: ret # Descriptor tables -# -# NOTE: The intel manual says gdt should be sixteen bytes aligned for -# efficiency reasons. However, there are machines which are known not -# to boot with misaligned GDTs, so alter this at your peril! If you alter -# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two -# empty GDT entries (one for NULL and one reserved). -# -# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is -# true for the Voyager Quad CPU card which will not boot without -# This directive. 16 byte aligment is recommended by intel. -# - .align 16 gdt: - .fill GDT_ENTRY_BOOT_CS,8,0 + .word 0, 0, 0, 0 # dummy + .word 0, 0, 0, 0 # unused .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) .word 0 # base address = 0 @@ -993,17 +1117,13 @@ gdt: .word 0x9200 # data read/write .word 0x00CF # granularity = 4096, 386 # (+5th nibble of limit) -gdt_end: - .align 4 - - .word 0 # alignment byte idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L - - .word 0 # alignment byte gdt_48: - .word gdt_end - gdt - 1 # gdt limit + .word 0x8000 # gdt limit=2048, + # 256 GDT entries + .word 0, 0 # gdt base (filled in later) # Include video setup & detection code diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 6d920d4b..803cbd0a 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -173,7 +173,7 @@ config CLOCK_DIV On many SoC style CPUs the master CPU clock is also used to drive on-chip peripherals. The clock that is distributed to these peripherals is sometimes a fixed ratio of the master clock - frequency. If so then set this to the divider ration of the + frequency. If so then set this to the divider ratio of the master clock to the peripheral clock. If not sure then select 1. config OLDMASK @@ -192,7 +192,7 @@ config PILOT3 Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII. config XCOPILOT_BUGS - bool " (X)Copilot support" + bool "(X)Copilot support" depends on PILOT3 help Support the bugs of Xcopilot. @@ -216,20 +216,20 @@ config DRAGEN2 Support for the DragenEngine II board. config DIRECT_IO_ACCESS - bool " Allow user to access IO directly" + bool "Allow user to access IO directly" depends on (UCSIMM || UCDIMM || DRAGEN2) help Disable the CPU internal registers protection in user mode, to allow a user application to read/write them. config INIT_LCD - bool " Initialize LCD" + bool "Initialize LCD" depends on (UCSIMM || UCDIMM || DRAGEN2) help Initialize the LCD controller of the 68x328 processor. config MEMORY_RESERVE - int " Memory reservation (MiB)" + int "Memory reservation (MiB)" depends on (UCSIMM || UCDIMM) help Reserve certain memory regions on 68x328 based boards. @@ -409,7 +409,7 @@ config MOD5272 Support for the Netburner MOD-5272 board. config ROMFS_FROM_ROM - bool " ROMFS image not RAM resident" + bool "ROMFS image not RAM resident" depends on (NETtel || SNAPGEAR) help The ROMfs filesystem will stay resident in the FLASH/ROM, not be diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index c18a8330..941955dc 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -290,7 +290,7 @@ void dump(struct pt_regs *fp) unsigned char *tp; int i; - printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); + printk(KERN_EMERG "\n" KERN_EMERG "CURRENT PROCESS:\n" KERN_EMERG "\n"); printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); if (current->mm) { @@ -301,7 +301,8 @@ void dump(struct pt_regs *fp) (int) current->mm->end_data, (int) current->mm->end_data, (int) current->mm->brk); - printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", + printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n" + KERN_EMERG "\n", (int) current->mm->start_stack, (int)(((unsigned long) current) + THREAD_SIZE)); } @@ -312,36 +313,35 @@ void dump(struct pt_regs *fp) fp->d0, fp->d1, fp->d2, fp->d3); printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(), - (unsigned int) fp); + printk(KERN_EMERG "\n" KERN_EMERG "USP: %08x TRAPFRAME: %08x\n", + (unsigned int) rdusp(), (unsigned int) fp); - printk(KERN_EMERG "\nCODE:"); + printk(KERN_EMERG "\n" KERN_EMERG "CODE:"); tp = ((unsigned char *) fp->pc) - 0x20; for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n"); + printk("\n" KERN_EMERG "\n"); - printk(KERN_EMERG "\nKERNEL STACK:"); + printk(KERN_EMERG "KERNEL STACK:"); tp = ((unsigned char *) fp) - 0x40; for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n"); - printk(KERN_EMERG "\n"); + printk("\n" KERN_EMERG "\n"); - printk(KERN_EMERG "\nUSER STACK:"); + printk(KERN_EMERG "USER STACK:"); tp = (unsigned char *) (rdusp() - 0x10); for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); - printk(KERN_EMERG "%08x ", (int) *sp++); + printk("\n" KERN_EMERG "%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); } - printk(KERN_EMERG "\n\n"); + printk("\n" KERN_EMERG "\n"); } /* diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index 7b21959e..1f78f321 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c @@ -36,10 +36,7 @@ #include #include #include - -#ifdef CONFIG_BLK_DEV_INITRD #include -#endif unsigned long memory_start; unsigned long memory_end; @@ -69,10 +66,14 @@ void (*mach_trap_init) (void); /* machine dependent timer functions */ unsigned long (*mach_gettimeoffset) (void); void (*mach_gettod) (int*, int*, int*, int*, int*, int*); -int (*mach_hwclk) (int, struct hwclk_time*); +int (*mach_hwclk) (int, struct rtc_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long); +unsigned int (*mach_get_ss)(void) = NULL; +int (*mach_get_rtc_pll)(struct rtc_pll_info *pll) = NULL; +int (*mach_set_rtc_pll)(struct rtc_pll_info *pll) = NULL; void (*mach_mksound)( unsigned int count, unsigned int ticks ); void (*mach_reset)( void ); +void (*mach_heartbeat)(int) = NULL; void (*waitbut)(void) = dummy_waitbut; void (*mach_debug_init)(void); void (*mach_halt)( void ); diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index c3494b84..3265b2d7 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c @@ -137,7 +137,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; @@ -190,6 +190,27 @@ asmlinkage int sys_ipc (uint call, int first, int second, default: return -EINVAL; } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = do_shmat (first, ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + } + case SHMDT: + return sys_shmdt (ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, ptr); + default: + return -ENOSYS; + } return -EINVAL; } diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c index 17649d25..9129b3a5 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68knommu/kernel/traps.c @@ -127,11 +127,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (stack + 1 > endstack) break; if (i % 8 == 0) - printk(KERN_EMERG "\n "); - printk(KERN_EMERG " %08lx", *stack++); + printk("\n" KERN_EMERG " "); + printk(" %08lx", *stack++); } + printk("\n"); - printk(KERN_EMERG "\nCall Trace:"); + printk(KERN_EMERG "Call Trace:"); i = 0; while (stack + 1 <= endstack) { addr = *stack++; @@ -146,12 +147,12 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (((addr >= (unsigned long) &_start) && (addr <= (unsigned long) &_etext))) { if (i % 4 == 0) - printk(KERN_EMERG "\n "); - printk(KERN_EMERG " [<%08lx>]", addr); + printk("\n" KERN_EMERG " "); + printk(" [<%08lx>]", addr); i++; } } - printk(KERN_EMERG "\n"); + printk("\n"); } void bad_super_trap(struct frame *fp) diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S index f2edb649..b9aa0ca2 100644 --- a/arch/m68knommu/platform/5307/head.S +++ b/arch/m68knommu/platform/5307/head.S @@ -64,6 +64,26 @@ negl %d0 /* negate bits */ .endm +#elif defined(CONFIG_M520x) +.macro GET_MEM_SIZE + clrl %d0 + movel MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ + andl #0x1f, %d2 /* Get only the chip select size */ + beq 3f /* Check if it is enabled */ + addql #1, %d2 /* Form exponent */ + moveql #1, %d0 + lsll %d2, %d0 /* 2 ^ exponent */ +3: + movel MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ + andl #0x1f, %d2 /* Get only the chip select size */ + beq 4f /* Check if it is enabled */ + addql #1, %d2 /* Form exponent */ + moveql #1, %d1 + lsll %d2, %d1 /* 2 ^ exponent */ + addl %d1, %d0 /* Total size of SDRAM in d0 */ +4: +.endm + #else #error "ERROR: I don't know how to probe your boards memory size?" #endif diff --git a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c index a57239ec..de93d065 100644 --- a/arch/m68knommu/platform/5307/ints.c +++ b/arch/m68knommu/platform/5307/ints.c @@ -41,7 +41,6 @@ static irq_node_t nodes[NUM_IRQ_NODES]; /* The number of spurious interrupts */ volatile unsigned int num_spurious; -unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; static irqreturn_t default_irq_handler(int irq, void *ptr) diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index 24781f00..e5668af1 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -3,7 +3,7 @@ /* * timers.c -- generic ColdFire hardware timer support. * - * Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com) */ /***************************************************************************/ @@ -44,6 +44,14 @@ unsigned int mcf_timerlevel = 5; extern void mcf_settimericr(int timer, int level); extern int mcf_timerirqpending(int timer); +#if defined(CONFIG_M532x) +#define __raw_readtrr __raw_readl +#define __raw_writetrr __raw_writel +#else +#define __raw_readtrr __raw_readw +#define __raw_writetrr __raw_writew +#endif + /***************************************************************************/ void coldfire_tick(void) @@ -57,7 +65,7 @@ void coldfire_tick(void) void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); - __raw_writew(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); + __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); @@ -76,7 +84,7 @@ unsigned long coldfire_timer_offset(void) unsigned long trr, tcn, offset; tcn = __raw_readw(TA(MCFTIMER_TCN)); - trr = __raw_readw(TA(MCFTIMER_TRR)); + trr = __raw_readtrr(TA(MCFTIMER_TRR)); offset = (tcn * (1000000 / HZ)) / trr; /* Check if we just wrapped the counters and maybe missed a tick */ @@ -120,7 +128,7 @@ void coldfire_profile_init(void) /* Set up TIMER 2 as high speed profile clock */ __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); - __raw_writew(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); + __raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); diff --git a/arch/m68knommu/platform/532x/spi-mcf532x.c b/arch/m68knommu/platform/532x/spi-mcf532x.c new file mode 100644 index 00000000..9fc5615d --- /dev/null +++ b/arch/m68knommu/platform/532x/spi-mcf532x.c @@ -0,0 +1,176 @@ +/***************************************************************************/ +/* + * linux/arch/m68knommu/platform/532x/spi-mcf532x.c + * + * Sub-architcture dependant initialization code for the Freescale + * 532x SPI module + * + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * Copyright Freescale Semiconductor, Inc 2006 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define SPI_NUM_CHIPSELECTS 0x04 +#define SPI_PAR_VAL 0xFFF0 /* Enable DIN, DOUT, CLK */ + +#define MCF532x_QSPI_IRQ_SOURCE (31) +#define MCF532x_QSPI_IRQ_VECTOR (64 + MCF532x_QSPI_IRQ_SOURCE) + +#define MCF532x_QSPI_PAR (0xFC0A405A) +#define MCF532x_QSPI_QMR (0xFC05C000) +#define MCF532x_INTC0_ICR (0xFC048040) +#define MCF532x_INTC0_IMRL (0xFC04800C) + +/* on 5329 EVB ADS7843 is connected to IRQ4 */ +#define ADS784x_IRQ_SOURCE 4 +#define ADS784x_IRQ_VECTOR (64+ADS784x_IRQ_SOURCE) +#define ADS7843_IRQ_LEVEL 2 + + +void coldfire_qspi_cs_control(u8 cs, u8 command) +{ +} + +#if defined(CONFIG_TOUCHSCREEN_ADS7843) +static struct coldfire_spi_chip ads784x_chip_info = { + .mode = SPI_MODE_0, + .bits_per_word = 8, + .del_cs_to_clk = 17, + .del_after_trans = 1, + .void_write_data = 0 +}; + +static struct ads7843_platform_data ads784x_platform_data = { + .model = 7843, + .vref_delay_usecs = 0, + .x_plate_ohms = 580, + .y_plate_ohms = 410 +}; +#endif + + +static struct spi_board_info spi_board_info[] = { +#if defined(CONFIG_TOUCHSCREEN_ADS7843) + { + .modalias = "ads7843", + .max_speed_hz = 125000 * 16, + .bus_num = 1, + .chip_select = 1, + .irq = ADS784x_IRQ_VECTOR, + .platform_data = &ads784x_platform_data, + .controller_data = &ads784x_chip_info + } +#endif +}; + +static struct coldfire_spi_master coldfire_master_info = { + .bus_num = 1, + .num_chipselect = SPI_NUM_CHIPSELECTS, + .irq_source = MCF532x_QSPI_IRQ_SOURCE, + .irq_vector = MCF532x_QSPI_IRQ_VECTOR, + .irq_mask = (0x01 << MCF532x_QSPI_IRQ_SOURCE), + .irq_lp = 0x5, /* Level */ + .par_val = 0, /* not used on 532x */ + .par_val16 = SPI_PAR_VAL, + .cs_control = coldfire_qspi_cs_control, +}; + +static struct resource coldfire_spi_resources[] = { + [0] = { + .name = "qspi-par", + .start = MCF532x_QSPI_PAR, + .end = MCF532x_QSPI_PAR, + .flags = IORESOURCE_MEM + }, + + [1] = { + .name = "qspi-module", + .start = MCF532x_QSPI_QMR, + .end = MCF532x_QSPI_QMR + 0x18, + .flags = IORESOURCE_MEM + }, + + [2] = { + .name = "qspi-int-level", + .start = MCF532x_INTC0_ICR + MCF532x_QSPI_IRQ_SOURCE, + .end = MCF532x_INTC0_ICR + MCF532x_QSPI_IRQ_SOURCE, + .flags = IORESOURCE_MEM + }, + + [3] = { + .name = "qspi-int-mask", + .start = MCF532x_INTC0_IMRL, + .end = MCF532x_INTC0_IMRL, + .flags = IORESOURCE_MEM + } +}; + +static struct platform_device coldfire_spi = { + .name = "coldfire-qspi", + .id = -1, + .resource = coldfire_spi_resources, + .num_resources = ARRAY_SIZE(coldfire_spi_resources), + .dev = { + .platform_data = &coldfire_master_info, + } +}; + +#if defined(CONFIG_TOUCHSCREEN_ADS7843) +static int __init init_ads7843(void) +{ + /* GPIO initiaalization */ + MCF_GPIO_PAR_IRQ = MCF_GPIO_PAR_IRQ_PAR_IRQ4(0); + /* EPORT initialization */ + MCF_EPORT_EPPAR = MCF_EPORT_EPPAR_EPPA4(MCF_EPORT_EPPAR_FALLING); + MCF_EPORT_EPDDR = 0; + MCF_EPORT_EPIER = MCF_EPORT_EPIER_EPIE4; + /* enable interrupt source */ + MCF_INTC0_ICR4 = ADS7843_IRQ_LEVEL; + MCF_INTC0_CIMR = ADS784x_IRQ_SOURCE; +} +#endif + +static int __init spi_dev_init(void) +{ + int retval = 0; +#if defined(CONFIG_TOUCHSCREEN_ADS7843) + init_ads7843(); +#endif + + retval = platform_device_register(&coldfire_spi); + if (retval < 0) + goto out; + + if (ARRAY_SIZE(spi_board_info)) + retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + + +out: + return retval; +} + +arch_initcall(spi_dev_init); diff --git a/arch/m68knommu/platform/532x/usb-mcf532x.c b/arch/m68knommu/platform/532x/usb-mcf532x.c new file mode 100644 index 00000000..c2a13b5c --- /dev/null +++ b/arch/m68knommu/platform/532x/usb-mcf532x.c @@ -0,0 +1,170 @@ +/*************************************************************************** + * usb-mcf532x.c - Platform level (mcf532x) USB initialization. + * + * Andrey Butok Andrey.Butok@freescale.com. + * Copyright Freescale Semiconductor, Inc 2006 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *************************************************************************** + * Changes: + * v0.01 31 March 2006 Andrey Butok + * Initial Release - developed on uClinux with 2.6.15.6 kernel + * + * WARNING: The MCF532x USB functionality was tested + * only with low-speed USB devices (cause of HW bugs). + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +/* Start address of HC registers.*/ +#define MCF532x_USB_HOST_REG_START (0xfc0b4000) +/* End address of HC registers */ +#define MCF532x_USB_HOST_REG_END (MCF532x_USB_HOST_REG_START+0x200) +/* USB Host Interrupt number */ +#define MCF532x_USB_HOST_INT_NUMBER (128+48) + +#ifdef CONFIG_USB_OTG +/* Start address of OTG module registers.*/ +#define MCF532x_USB_OTG_REG_START (0xfc0b0000) +/* End address of OTG module registers */ +#define MCF532x_USB_OTG_REG_END (MCF532x_USB_OTG_REG_START+0x200) +/* USB OTG Interrupt number */ +#define MCF532x_USB_OTG_INT_NUMBER (128+47) +#endif + +/*-------------------------------------------------------------------------*/ + +static void +usb_release(struct device *dev) +{ + /* normally not freed */ +} + +/* + * USB Host module structures + */ +static struct resource ehci_host_resources[] = { + { + .start = MCF532x_USB_HOST_REG_START, + .end = MCF532x_USB_HOST_REG_END, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF532x_USB_HOST_INT_NUMBER, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ehci_host_device = { + .name = "ehci", + .id = 1, + .dev = { + .release = usb_release, + .dma_mask = 0x0}, + .num_resources = ARRAY_SIZE(ehci_host_resources), + .resource = ehci_host_resources, +}; + +/* + * USB OTG module structures. + */ +#ifdef CONFIG_USB_OTG +static struct resource ehci_otg_resources[] = { + { + .start = MCF532x_USB_OTG_REG_START, + .end = MCF532x_USB_OTG_REG_END, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF532x_USB_OTG_INT_NUMBER, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ehci_otg_device = { + .name = "ehci", + .id = 0, + .dev = { + .release = usb_release, + .dma_mask = 0x0}, + .num_resources = ARRAY_SIZE(ehci_otg_resources), + .resource = ehci_otg_resources, +}; +#endif + +typedef volatile u8 vuint8; /* 8 bits */ + +static int __init +mcf532x_usb_init(void) +{ + int status; + + /* + * Initialize the clock divider for the USB: + */ +#ifdef CONFIG_CLOCK_240MHz + /* + * CPU oerating on 240Mhz (MISCCR[USBDIV]=1) + */ + (*(volatile u16 *) (0xFC0A0010)) |= (0x0002); +#elif defined(CONFIG_CLOCK_180MHz) + /* + * CPU oerating on 180Mhz (MISCCR[USBDIV]=0) + */ + (*(volatile u16 *) (0xFC0A0010)) |= ~(0x0002); +#else +#error "CONFIG_CLOCK_240MHz or CONFIG_CLOCK_180MHz must be defined for MCF532x." +#endif + /* + * Register USB Host device: + */ + status = platform_device_register(&ehci_host_device); + if (status) { + pr_info + ("USB-MCF532x: Can't register MCF532x USB Host device, %d\n", + status); + return -ENODEV; + } + pr_info("USB-MCF532x: MCF532x USB Host device is registered\n"); + +#ifdef CONFIG_USB_OTG + /* + * Register USB OTG device: + * Done only USB Host. + * TODO: Device and OTG functinality. + */ + status = platform_device_register(&ehci_otg_device); + if (status) { + pr_info + ("USB-MCF532x: Can't register MCF532x USB OTG device, %d\n", + status); + return -ENODEV; + } + pr_info("USB-MCF532x: MCF532x USB OTG device is registered\n"); +#endif + + return 0; +} + +subsys_initcall(mcf532x_usb_init); diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c index c5482e36..1b36f626 100644 --- a/arch/m68knommu/platform/68360/config.c +++ b/arch/m68knommu/platform/68360/config.c @@ -114,7 +114,7 @@ void BSP_gettod (int *yearp, int *monp, int *dayp, { } -int BSP_hwclk(int op, struct hwclk_time *t) +int BSP_hwclk(int op, struct rtc_time *t) { if (!op) { /* read */ diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S index 2ea51479..2ef06242 100644 --- a/arch/m68knommu/platform/68360/head-ram.S +++ b/arch/m68knommu/platform/68360/head-ram.S @@ -25,6 +25,7 @@ .global _periph_base #define RAMEND (CONFIG_RAMBASE + CONFIG_RAMSIZE) +#define ROMEND (CONFIG_ROMBASE + CONFIG_ROMSIZE) #define REGB 0x1000 #define PEPAR (_dprbase + REGB + 0x0016) @@ -175,7 +176,7 @@ configure_chip_select_0: move.l %d0, BR0 configure_chip_select_1: - move.l #__rom_end, %d0 + move.l #ROMEND, %d0 subi.l #__rom_start, %d0 subq.l #0x01, %d0 eori.l #SIM_OR_MASK, %d0 diff --git a/arch/m68knommu/platform/68VZ328/screen.xbm b/arch/m68knommu/platform/68VZ328/screen.xbm new file mode 100644 index 00000000..19c5504e --- /dev/null +++ b/arch/m68knommu/platform/68VZ328/screen.xbm @@ -0,0 +1,804 @@ +/* Created with The GIMP */ +#define screen_width 320 +#define screen_height 240 +static unsigned char screen_bits[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x95, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x4f, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6b, 0xa5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x29, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x56, 0xa9, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0xf1, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, + 0x7f, 0xe0, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x25, 0x55, 0xff, 0xff, 0xff, 0x0f, + 0xc0, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0x3f, 0xc0, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x73, 0x52, 0x95, + 0xff, 0xff, 0xff, 0x87, 0xcf, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x3f, 0x8f, 0xff, 0x79, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x14, 0x55, 0x55, 0xff, 0x3f, 0x8e, 0xc7, 0xff, 0xf1, 0x78, 0x86, + 0x8f, 0xe3, 0x78, 0xfe, 0xf1, 0xfc, 0xf0, 0x31, 0x33, 0xfc, 0xe1, 0xe3, + 0xff, 0x8f, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbf, 0x6a, 0xaa, 0x4a, 0xff, 0x3f, 0x8e, 0xe3, + 0xff, 0xf1, 0x78, 0x00, 0x8f, 0xe3, 0x38, 0xfe, 0x71, 0x3c, 0xe0, 0x11, + 0x03, 0x78, 0xc0, 0xe3, 0xff, 0x8f, 0xff, 0x08, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x2b, 0x55, 0xa9, + 0xff, 0x3f, 0x8e, 0xe3, 0xff, 0xf1, 0x78, 0x18, 0x8f, 0xe3, 0x31, 0xff, + 0x31, 0x3e, 0xc6, 0x01, 0xc3, 0x78, 0x8c, 0xe3, 0xff, 0xc7, 0xff, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x57, 0x95, 0x2a, 0x55, 0xff, 0x3f, 0x8e, 0xe3, 0xff, 0xf1, 0x78, 0x1c, + 0x8f, 0xe3, 0x91, 0xff, 0x11, 0x1f, 0xc7, 0xe1, 0xe3, 0x38, 0x8e, 0xe3, + 0xff, 0xe1, 0xff, 0x30, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x69, 0x55, 0xa5, 0x12, 0xff, 0x3f, 0x8e, 0xe3, + 0xff, 0xf1, 0x78, 0x1c, 0x8f, 0xe3, 0xc3, 0xff, 0x81, 0x1f, 0xc0, 0xf1, + 0xe3, 0x38, 0x80, 0xe3, 0xff, 0xf0, 0xff, 0x78, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x5a, 0xa6, 0x2a, 0x49, + 0xff, 0x3f, 0x8e, 0xc3, 0xff, 0xf1, 0x78, 0x1c, 0x8f, 0xe3, 0x83, 0xff, + 0x01, 0x1f, 0xc0, 0xf1, 0xe3, 0x38, 0x80, 0xe3, 0x7f, 0xfc, 0xff, 0x78, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, + 0x4d, 0x51, 0x92, 0x54, 0xff, 0x3f, 0x8e, 0xc7, 0xff, 0xf1, 0x78, 0x1c, + 0x8f, 0xe3, 0x11, 0xff, 0x11, 0x1e, 0xff, 0xf1, 0xe3, 0x38, 0xfe, 0xe3, + 0x3f, 0xfe, 0xff, 0x78, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xd7, 0xaa, 0xac, 0x54, 0x25, 0xff, 0x3f, 0x86, 0x07, + 0xcf, 0xf1, 0x78, 0x1c, 0x8f, 0xe1, 0x19, 0xff, 0x31, 0x1c, 0xce, 0xf1, + 0xe3, 0x38, 0x9c, 0xe3, 0x3f, 0x80, 0xe3, 0x71, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0x52, 0x22, 0x25, 0xa9, + 0xff, 0x3f, 0x80, 0x0f, 0xc0, 0xf1, 0x78, 0x1c, 0x0f, 0xe0, 0x38, 0xfe, + 0x71, 0x38, 0xc0, 0xf1, 0xe3, 0x78, 0x80, 0xe3, 0x3f, 0x80, 0xe3, 0x01, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6a, + 0x29, 0x95, 0x94, 0x4a, 0xff, 0x7f, 0x98, 0x3f, 0xf0, 0xf1, 0x78, 0x1c, + 0x1f, 0xe6, 0x3c, 0xfe, 0xf1, 0xf8, 0xe0, 0xf1, 0xe3, 0xf8, 0xc1, 0xe3, + 0x3f, 0x80, 0xe3, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x55, 0x55, 0xa9, 0xa2, 0x28, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x95, 0x54, 0x54, 0x54, 0xca, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0xa5, + 0x12, 0x43, 0x15, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x51, 0x49, 0xaa, 0x34, 0xca, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x2e, 0xa9, 0x92, 0x84, 0x29, 0x92, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xa2, 0x4a, + 0x28, 0xb3, 0xa4, 0x4a, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x87, 0xaa, 0x52, 0x4a, 0x89, 0x96, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x9e, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0x3c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x29, 0x09, 0xa5, 0x52, 0x51, 0x69, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x9e, 0xff, 0xff, 0x9f, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0xa4, 0x64, + 0x35, 0x28, 0x29, 0x2d, 0xff, 0xff, 0xf0, 0x84, 0x3f, 0x98, 0xf0, 0xe1, + 0x9f, 0xcf, 0xc9, 0xc1, 0x07, 0x1e, 0x9e, 0xf0, 0xfc, 0x84, 0x0f, 0xcc, + 0x84, 0x0f, 0xff, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x94, 0x2a, 0x15, 0x89, 0xae, 0x94, 0xa2, 0xff, 0x7f, 0xe6, 0x18, + 0x7f, 0x1e, 0xe3, 0xcc, 0x9f, 0xcf, 0xc9, 0x9f, 0x73, 0xce, 0x1c, 0xe3, + 0xfc, 0x18, 0xe7, 0xcc, 0x18, 0x67, 0xfe, 0x3c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x8f, 0x4b, 0x85, 0xa4, 0x55, 0x22, 0x65, 0xbd, + 0xff, 0x3f, 0xcf, 0x3c, 0x7f, 0x9e, 0x67, 0xce, 0x9f, 0xcf, 0xf1, 0x9f, + 0x79, 0xe6, 0x99, 0xe7, 0xe0, 0x3c, 0xf3, 0xcc, 0x3c, 0x73, 0xfe, 0x3c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x10, 0x29, 0xa9, + 0x2a, 0x95, 0x94, 0x02, 0xff, 0x3f, 0xcf, 0x3c, 0x7f, 0x9e, 0x67, 0xc0, + 0x9f, 0xcf, 0xf9, 0x81, 0x79, 0xe6, 0x99, 0xe7, 0xfc, 0x3c, 0xf3, 0xcc, + 0x3c, 0x03, 0xfe, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x51, 0xd6, 0x24, 0x51, 0x89, 0xa4, 0xaa, 0xba, 0xff, 0x3f, 0xcf, 0x3c, + 0x7f, 0x9e, 0x67, 0xfe, 0x9f, 0xcf, 0xf9, 0x9c, 0x79, 0xe6, 0x99, 0xe7, + 0xfc, 0x3c, 0xf3, 0xcc, 0x3c, 0xf3, 0xff, 0x3c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x24, 0x29, 0x4a, 0x26, 0x1b, 0x55, 0x55, 0x55, + 0xff, 0x3f, 0xcf, 0x3c, 0x7f, 0x9e, 0x67, 0xfe, 0x9f, 0xcf, 0xf9, 0x9c, + 0x33, 0xe6, 0x99, 0xe7, 0xfc, 0x3c, 0x67, 0xcc, 0x3c, 0xf3, 0xff, 0x3c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x93, 0x84, 0x52, 0x59, + 0x51, 0xa5, 0x54, 0x95, 0xff, 0x7f, 0xe6, 0x3c, 0x7f, 0x9e, 0xe7, 0xdc, + 0x9f, 0xe7, 0xf9, 0x8c, 0x47, 0xce, 0x9c, 0xe7, 0xfc, 0x3c, 0x8f, 0xcc, + 0x3c, 0xe7, 0xfe, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaf, + 0x48, 0x52, 0x49, 0x95, 0x55, 0x55, 0x55, 0x8a, 0xff, 0xff, 0xf0, 0x3c, + 0xff, 0x98, 0xe7, 0xe1, 0x1f, 0xf0, 0xf9, 0x11, 0x7f, 0x1e, 0x9e, 0xe7, + 0xc0, 0x3c, 0xff, 0xcc, 0x3c, 0x0f, 0xff, 0x3c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xa1, 0x2a, 0x49, 0xa4, 0xaa, 0xac, 0x54, 0x49, 0xe5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0x73, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x95, 0xa4, 0xaa, 0xa8, 0x8a, + 0x26, 0xa5, 0x6a, 0x2d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x54, + 0x22, 0x40, 0x4a, 0x4a, 0x69, 0xa8, 0x2c, 0x55, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x5f, 0x0a, 0x92, 0xae, 0xa9, 0x62, 0xa5, 0x4b, 0xa2, 0x92, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0xa1, 0x51, 0x89, 0x4c, 0xb5, + 0x26, 0x24, 0x55, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x25, 0x4a, + 0x0a, 0x56, 0x55, 0x48, 0x55, 0x55, 0x29, 0x55, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xa8, 0x52, 0xc8, 0x40, 0x65, 0xa5, 0x52, 0x95, 0xaa, 0x92, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x12, 0x29, 0x93, 0xad, 0x28, 0x2a, + 0x4b, 0xa9, 0x26, 0x29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x4a, 0x09, + 0x29, 0x28, 0x44, 0x21, 0xa9, 0x55, 0x52, 0x95, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x17, 0x91, 0xa4, 0x94, 0x45, 0xb9, 0x9c, 0x54, 0x93, 0xaa, 0x52, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0x24, 0x95, 0xc2, 0xb0, 0x5a, 0x45, + 0x96, 0xaa, 0x92, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2a, 0x88, 0x40, + 0x54, 0xcb, 0x49, 0xa6, 0x51, 0x25, 0xa9, 0x52, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x88, 0x4a, 0x55, 0x57, 0x08, 0xd5, 0x90, 0x5c, 0xa9, 0x6a, 0x9a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x5f, 0x25, 0x94, 0x4a, 0x82, 0xf2, 0x9a, 0x53, + 0x25, 0x54, 0xad, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x28, 0x45, 0x50, + 0xaa, 0x14, 0xd0, 0x51, 0xa2, 0x55, 0x0a, 0x89, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x13, 0x85, 0x10, 0x55, 0x79, 0xc2, 0xef, 0x25, 0x55, 0xa5, 0x6a, 0x52, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x90, 0xa2, 0xaa, 0xaa, 0x06, 0x69, 0xc8, 0x54, + 0x2d, 0x6a, 0xaa, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x4b, 0x54, 0x48, 0xa5, + 0xb0, 0x94, 0x8a, 0x24, 0x86, 0x1b, 0x05, 0x52, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x49, 0x25, 0xaa, 0xa4, 0x8a, 0x56, 0xe5, 0x54, 0xd3, 0x49, 0xe9, 0x4a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x57, 0x24, 0x14, 0x95, 0x52, 0x54, 0x49, 0x6b, 0x25, + 0x2d, 0x24, 0x15, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x93, 0xa4, 0xca, 0x54, 0x2d, + 0x15, 0xa9, 0x26, 0x91, 0xc5, 0x56, 0xd5, 0xab, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa0, + 0x12, 0x20, 0x2a, 0x92, 0xa8, 0x4a, 0xb9, 0x56, 0x7a, 0x50, 0x6a, 0x4a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x15, 0x0a, 0x29, 0xb1, 0xd5, 0x66, 0x54, 0x8f, 0x30, + 0x05, 0x57, 0xab, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xa8, 0xd4, 0x4a, 0x45, 0x53, + 0x52, 0xd3, 0xb2, 0xaa, 0xd5, 0xa2, 0x4a, 0x55, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x85, + 0x0a, 0x48, 0x2a, 0xa8, 0x32, 0xaa, 0xa9, 0x4a, 0x54, 0x54, 0xaa, 0x2a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xab, 0x62, 0x50, 0x22, 0x52, 0x55, 0xd9, 0x15, 0x55, 0x29, + 0x45, 0xf4, 0xb5, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2a, 0x25, 0x92, 0x49, 0x13, + 0x09, 0xaa, 0x25, 0xba, 0x52, 0x07, 0x48, 0x31, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x59, 0xaa, + 0x89, 0x20, 0x34, 0xa5, 0xd4, 0xd5, 0xaa, 0x85, 0x3c, 0x52, 0x57, 0x95, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x0a, 0x01, 0xa8, 0x92, 0xaa, 0x94, 0x4a, 0x70, 0xb4, 0x54, + 0x95, 0x55, 0xa9, 0x54, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x42, 0xa4, 0x0a, 0x51, 0x09, 0xa5, + 0x5d, 0x9b, 0x12, 0x25, 0xfb, 0x44, 0x55, 0xab, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x28, 0x01, + 0x50, 0x4d, 0x56, 0x91, 0x64, 0x95, 0x52, 0xb5, 0x49, 0xb7, 0x4a, 0xaa, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x15, 0x03, 0xda, 0x0e, 0x62, 0x89, 0xba, 0x09, 0x47, 0xa9, 0x08, + 0x52, 0x49, 0xaa, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x40, 0x51, 0x0b, 0xc1, 0x15, 0xee, 0x90, + 0xfe, 0x52, 0x15, 0xc5, 0x14, 0x55, 0xd5, 0x8a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x63, 0x00, 0x90, + 0x2a, 0xa1, 0x15, 0xd6, 0x08, 0x4f, 0xd8, 0xa8, 0xea, 0xaa, 0x2a, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xcf, 0x10, 0x00, 0x49, 0x12, 0x2d, 0x63, 0x17, 0xab, 0xa0, 0x12, 0x95, + 0x12, 0xaa, 0x48, 0x64, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe7, 0x82, 0x40, 0xa4, 0x86, 0xc8, 0x98, 0x54, + 0xb5, 0xab, 0xe5, 0x6a, 0xd5, 0xa5, 0x16, 0x18, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x68, 0x90, 0x82, + 0xd4, 0x25, 0x4a, 0x39, 0x79, 0x10, 0x12, 0x0a, 0x55, 0xb5, 0x06, 0x88, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0x6c, 0x42, 0x20, 0x29, 0x28, 0x50, 0x29, 0x4b, 0x15, 0xb5, 0xd6, 0xaa, + 0x72, 0x2a, 0xad, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xbf, 0x24, 0x2c, 0x00, 0x50, 0x23, 0x55, 0xfa, 0xff, + 0x5d, 0x89, 0x52, 0x52, 0x59, 0xb5, 0xff, 0xcd, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0x8b, 0x41, 0x24, 0x5a, + 0xac, 0x82, 0xfe, 0xff, 0xaf, 0xd5, 0xaa, 0x5a, 0x5d, 0xef, 0x6f, 0x57, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, + 0xe4, 0x34, 0x27, 0x8a, 0x12, 0xa8, 0xff, 0xff, 0xff, 0x56, 0xaa, 0x95, + 0xc4, 0x78, 0x7b, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x35, 0x7d, 0x00, 0x11, 0x42, 0xaa, 0xe5, 0xff, 0xff, + 0xff, 0x24, 0x51, 0xd4, 0xb2, 0xda, 0x1f, 0xa8, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x08, 0x1f, 0x42, 0x59, 0x28, + 0xba, 0xf4, 0xff, 0xff, 0xff, 0x5b, 0x2d, 0x53, 0x95, 0xfe, 0x11, 0xa9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xeb, + 0x7f, 0xeb, 0xa6, 0x92, 0x14, 0xf9, 0xff, 0xff, 0xff, 0xcf, 0xaa, 0xaa, + 0xaa, 0xbf, 0x1f, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x17, 0xf8, 0x17, 0x72, 0x02, 0x88, 0xd2, 0xfc, 0xff, 0xff, + 0xff, 0xef, 0xaa, 0x4a, 0xe9, 0xd5, 0xdf, 0xa5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xd1, 0x1e, 0x11, 0xb1, 0xa5, + 0x2a, 0xfe, 0xff, 0xff, 0xff, 0xbf, 0xd4, 0x52, 0xb5, 0xef, 0x25, 0xd4, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x51, 0xff, + 0x07, 0x94, 0x08, 0xa4, 0x54, 0xff, 0xff, 0xff, 0xcf, 0x7f, 0xb5, 0x54, + 0xfd, 0x70, 0x55, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x26, 0xff, 0x17, 0x2d, 0xb6, 0x12, 0x0a, 0xff, 0xff, 0xff, + 0x8f, 0x7f, 0x8d, 0xaa, 0x8a, 0x56, 0x55, 0x49, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe2, 0x77, 0x2b, 0x37, 0x91, 0x08, + 0xd5, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xd5, 0xaa, 0xaa, 0x52, 0x4a, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xfd, 0xff, + 0x81, 0xc1, 0x59, 0xd0, 0xe1, 0xff, 0xff, 0xff, 0x07, 0xff, 0x2a, 0x95, + 0x54, 0x55, 0x65, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xaf, 0xfd, 0xbd, 0x49, 0x8c, 0x58, 0x8a, 0xd5, 0xff, 0xff, 0xff, + 0xe7, 0xff, 0x49, 0x51, 0x45, 0x55, 0x4d, 0xb5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0xbe, 0x3f, 0xc4, 0xd5, 0x02, 0x79, + 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x4a, 0xba, 0x52, 0xf9, 0x4a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa5, 0xff, 0x97, + 0x64, 0x52, 0xda, 0x1c, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa5, 0xa8, + 0x8a, 0x54, 0x15, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xd5, 0xdf, 0x4f, 0x91, 0x22, 0x2d, 0xc2, 0xe5, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x93, 0x56, 0x6a, 0x55, 0xd5, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf5, 0xef, 0x25, 0x5c, 0x43, 0x16, 0xaf, + 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x92, 0x2a, 0x2b, 0x55, 0x2a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xdb, 0xfb, 0x43, + 0x65, 0x21, 0x91, 0x13, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x49, + 0x51, 0x52, 0x55, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xb7, 0xf0, 0x7f, 0x00, 0x7b, 0xea, 0x3c, 0xd1, 0xea, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x27, 0x6a, 0x2d, 0x55, 0x55, 0xab, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x5b, 0xfc, 0x7d, 0xac, 0xc6, 0x11, 0xe5, 0x46, + 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x95, 0xd2, 0x4a, 0xb2, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2d, 0xfe, 0x0f, 0x82, + 0xfc, 0x90, 0x54, 0x32, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0xd5, + 0x5a, 0xaa, 0x55, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x17, 0xdf, 0x1e, 0xc2, 0xa9, 0x23, 0xca, 0x46, 0xe5, 0xff, 0xff, 0x3f, + 0xf8, 0xff, 0x97, 0x2a, 0x55, 0xad, 0x94, 0x5a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0xc5, 0xff, 0x07, 0xd5, 0x6c, 0xab, 0x12, 0x9a, + 0xe4, 0x0f, 0xff, 0x1f, 0xe0, 0xff, 0x57, 0xa9, 0x55, 0xa5, 0xda, 0xaa, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa1, 0xef, 0xd1, 0xac, + 0xc6, 0xa5, 0xea, 0x5c, 0xf3, 0x07, 0xfe, 0x0f, 0xc0, 0xff, 0x4f, 0x55, + 0xaa, 0x5a, 0x55, 0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaf, + 0xf0, 0xfb, 0xa8, 0xa5, 0xf2, 0x18, 0x56, 0x41, 0xf7, 0x03, 0xfc, 0x07, + 0x80, 0xff, 0xaf, 0xaa, 0xaa, 0x4a, 0xad, 0x56, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0xd0, 0xbf, 0x41, 0x52, 0x0e, 0xc6, 0xaa, 0x68, + 0xfa, 0x03, 0xfc, 0x07, 0x80, 0xff, 0x9f, 0x52, 0xd5, 0x6a, 0xab, 0xd5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x17, 0xfd, 0x1d, 0x28, 0x2a, + 0x51, 0x75, 0x55, 0x4d, 0xe4, 0x03, 0xf8, 0x03, 0x03, 0xff, 0xaf, 0xaa, + 0x6a, 0xad, 0xaa, 0x4a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3b, + 0xfc, 0x9f, 0x00, 0x58, 0x92, 0x22, 0x6a, 0xd3, 0xed, 0xf3, 0xf8, 0xc3, + 0x0f, 0xff, 0xaf, 0xaa, 0xae, 0xaa, 0xaa, 0xda, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0a, 0xfe, 0x06, 0x7a, 0x4e, 0x52, 0x94, 0x36, 0x4c, + 0xf6, 0xb9, 0xf9, 0xc3, 0x1b, 0xff, 0x9f, 0xaa, 0x52, 0xaa, 0xaa, 0x6a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0xb6, 0x03, 0x52, 0x93, + 0x95, 0x52, 0x46, 0x55, 0xf6, 0xb9, 0xf9, 0xe3, 0x17, 0xfe, 0x4f, 0xd5, + 0xaa, 0xd5, 0xaa, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xa1, + 0xff, 0xa2, 0x2a, 0x31, 0x18, 0xba, 0x92, 0x55, 0xcb, 0x79, 0xf9, 0xe3, + 0x17, 0xfe, 0x6f, 0x29, 0xad, 0x54, 0xad, 0xb6, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x4f, 0x80, 0x3f, 0x49, 0xa8, 0xef, 0x75, 0x47, 0x2b, 0x53, + 0xef, 0x79, 0xf9, 0xe3, 0x1f, 0xfe, 0x9f, 0xa4, 0xaa, 0x6a, 0x55, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b, 0xe0, 0x8d, 0x20, 0x6e, 0x84, + 0x53, 0xa8, 0x29, 0xb1, 0xeb, 0xf9, 0xf1, 0xe3, 0x1f, 0xfe, 0x5f, 0xb5, + 0xaa, 0xaa, 0x56, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, + 0x4f, 0x39, 0x42, 0x38, 0x15, 0x55, 0x92, 0x6d, 0xcc, 0xfb, 0x01, 0xe0, + 0x1f, 0xfe, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0x4a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x45, 0x78, 0xd3, 0x9c, 0x2a, 0x1a, 0x76, 0x11, 0x13, 0xcc, + 0xed, 0xf3, 0x06, 0xc3, 0x1f, 0xfe, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0x69, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x23, 0xfc, 0xd3, 0x24, 0x8d, 0x60, + 0x8a, 0x54, 0xd5, 0x78, 0xd2, 0x67, 0x03, 0x80, 0x0f, 0xff, 0x5f, 0x55, + 0x55, 0x55, 0xb5, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x01, 0x6e, + 0x70, 0x10, 0x58, 0x15, 0xa8, 0x4e, 0xcd, 0xa4, 0xca, 0x37, 0x00, 0x00, + 0xfe, 0xff, 0xaf, 0x54, 0xaa, 0xda, 0x56, 0xd5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x10, 0xbf, 0x35, 0xc9, 0xb1, 0xf7, 0x3a, 0xa9, 0xd1, 0xa8, + 0xd3, 0x1f, 0x00, 0x00, 0xf8, 0xff, 0x5f, 0x8d, 0xd5, 0x56, 0x55, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x37, 0xc0, 0x16, 0x94, 0x55, 0x92, 0x2a, + 0x12, 0x5d, 0x9d, 0x4a, 0xd0, 0x07, 0x00, 0x00, 0x80, 0xff, 0x5f, 0xab, + 0x54, 0xd5, 0x56, 0x75, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x0c, 0x8f, + 0x20, 0x4b, 0xb7, 0xd4, 0xe2, 0x92, 0x28, 0xa9, 0xf7, 0x03, 0x00, 0x00, + 0x00, 0xff, 0xbf, 0xa4, 0xae, 0x2a, 0xa9, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x15, 0xc2, 0xa3, 0x9c, 0x4f, 0x91, 0x72, 0x11, 0x57, 0xab, 0x95, + 0xd3, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xbf, 0x5a, 0x51, 0xab, 0xb5, 0xaa, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbf, 0x0f, 0xc0, 0x04, 0x51, 0x46, 0xa5, 0x19, + 0x57, 0x65, 0x32, 0xc9, 0xcd, 0x01, 0x00, 0x00, 0x00, 0xfe, 0x5f, 0x55, + 0xae, 0xaa, 0xaa, 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x60, 0x24, + 0x48, 0x93, 0xa5, 0x28, 0x4a, 0x29, 0x15, 0x45, 0xda, 0x01, 0x00, 0x00, + 0x30, 0xfe, 0x5f, 0xd5, 0xb2, 0xaa, 0xaa, 0x6a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0xd0, 0xa5, 0xaa, 0x24, 0xfd, 0xfb, 0xa8, 0xaa, 0xea, 0x67, + 0xe8, 0x07, 0x00, 0x00, 0x18, 0xff, 0xbf, 0x55, 0x2d, 0x54, 0x55, 0xad, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x5f, 0x00, 0xb0, 0x52, 0x41, 0x95, 0xaa, 0x91, + 0x5a, 0x8c, 0xd2, 0x74, 0xcb, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xbf, 0x5a, + 0xa5, 0xab, 0x55, 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x7c, 0x73, + 0xa6, 0x4e, 0x79, 0x8b, 0xb2, 0x52, 0x15, 0x65, 0xee, 0x1f, 0x00, 0xe0, + 0x81, 0x9f, 0xff, 0xaa, 0x59, 0xb4, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x07, 0x81, 0xbf, 0x55, 0x19, 0x52, 0x25, 0x5f, 0xa0, 0x2a, 0xaf, 0x4e, + 0xd8, 0x3f, 0x00, 0x3c, 0x80, 0x1f, 0x7f, 0xaa, 0xaa, 0x9b, 0xaa, 0x6a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x97, 0x41, 0xf7, 0x15, 0x46, 0xad, 0xae, 0x14, + 0x56, 0xa5, 0x54, 0x4d, 0xe5, 0xff, 0xc0, 0x07, 0x98, 0x3f, 0x7c, 0x55, + 0xb5, 0x54, 0x55, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x78, 0xbd, 0xda, + 0x41, 0x14, 0xa2, 0xf2, 0xdb, 0x54, 0x16, 0x5c, 0xb4, 0xff, 0xff, 0x01, + 0x1e, 0x3f, 0xf8, 0xbd, 0xaa, 0x56, 0x55, 0x2d, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x4f, 0xbd, 0x17, 0x20, 0xce, 0xca, 0x9d, 0x8a, 0x44, 0x32, 0xe9, 0xb6, + 0xc9, 0x3f, 0x3f, 0x80, 0x0f, 0x7f, 0xf8, 0xa5, 0x55, 0xb9, 0xaa, 0xd5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x43, 0xaf, 0xb3, 0x54, 0x21, 0x6c, 0x84, 0x4a, + 0x76, 0xad, 0xaa, 0x9c, 0xe9, 0x7b, 0x00, 0xe0, 0x01, 0xff, 0xf9, 0xab, + 0x6a, 0x8b, 0x6a, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xd9, 0x32, 0xe7, + 0x8e, 0x8a, 0xd2, 0x9d, 0xa6, 0x22, 0xd5, 0x54, 0xd2, 0xf3, 0x00, 0xf8, + 0x00, 0xfe, 0xff, 0xb5, 0x5a, 0x75, 0x55, 0xad, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, + 0xbe, 0x7c, 0xb5, 0x32, 0x2c, 0x5c, 0xd4, 0xa4, 0x34, 0xad, 0xe9, 0x1e, + 0xe9, 0xf3, 0x03, 0x3f, 0x00, 0xfe, 0xff, 0xab, 0xaa, 0x55, 0x5d, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x25, 0x9c, 0x6a, 0x67, 0xd1, 0x43, 0x6a, 0xb6, + 0x2a, 0x25, 0x56, 0xf2, 0xeb, 0xe1, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x57, + 0xab, 0x56, 0xab, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf7, 0x0f, 0x29, 0xba, + 0x12, 0xbb, 0x79, 0x2b, 0xb5, 0xaa, 0x33, 0x47, 0xfa, 0xc1, 0xff, 0x0f, + 0x00, 0xf8, 0xff, 0xd7, 0xda, 0xaa, 0x6a, 0xb5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, + 0xff, 0x3b, 0x1b, 0xd9, 0x4e, 0x20, 0xd9, 0x1a, 0xa5, 0xaa, 0x34, 0xa5, + 0xfa, 0xc1, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x5f, 0x6b, 0xb5, 0x5d, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xbf, 0xad, 0x05, 0x99, 0xa9, 0x2a, 0xbb, 0x0a, 0xc8, + 0x6a, 0x55, 0x17, 0x17, 0xfa, 0x80, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xbf, + 0xaa, 0xad, 0xaa, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x4e, 0x3e, 0x6d, 0x4a, + 0xa6, 0x15, 0xf5, 0x29, 0x29, 0xa5, 0x74, 0xa7, 0xfe, 0x00, 0xff, 0x00, + 0x00, 0xf0, 0xff, 0x5f, 0xb5, 0x56, 0x6b, 0x55, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, + 0x27, 0x2d, 0x2c, 0x5d, 0x21, 0x8d, 0x2d, 0x45, 0xab, 0x54, 0x97, 0x6b, + 0x7d, 0x00, 0x1e, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xab, 0x5a, 0xad, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfb, 0xb5, 0xe6, 0x46, 0x8f, 0x56, 0x59, 0xe3, 0x56, + 0x55, 0xa9, 0x2a, 0x53, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, + 0x6a, 0xd7, 0x6a, 0xad, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xfe, 0x38, 0x2b, 0xd1, 0x4d, + 0x52, 0x55, 0x54, 0x56, 0x69, 0xad, 0xca, 0x89, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0x7f, 0x5b, 0x59, 0xab, 0x56, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0xa6, 0x12, 0x2f, 0xf2, 0x09, 0xc0, 0x40, 0xa9, 0x2e, 0x54, 0x8d, 0xea, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x6d, 0xd7, 0x5a, 0xa9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xbf, 0xd6, 0x2a, 0x43, 0x6c, 0x29, 0x52, 0x3d, 0x88, + 0x92, 0x56, 0xd5, 0xa6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xaa, 0xd5, 0xaa, 0xad, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbd, 0x37, 0x06, 0xe9, 0x25, + 0x00, 0xa0, 0x14, 0xa0, 0x5a, 0xa9, 0xca, 0xd4, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0x55, 0x35, 0xab, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xdf, + 0x59, 0xc3, 0x2e, 0x36, 0x1e, 0x91, 0x51, 0x50, 0x15, 0x55, 0xc5, 0xea, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x2f, 0xd5, 0x56, 0xd5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xab, 0x21, 0x40, 0x51, 0xa2, 0x8a, 0x80, 0xdd, 0xa5, + 0xae, 0xac, 0xc6, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xd7, 0xad, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0xe4, 0xba, 0x42, 0x65, 0xb5, + 0x8e, 0xc8, 0xed, 0x70, 0x4b, 0xb5, 0xc6, 0xfa, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xbf, 0xff, 0xbf, 0x56, 0xd5, 0xb6, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2f, 0x53, + 0x05, 0x48, 0xa9, 0xb0, 0x56, 0x67, 0x6f, 0xaa, 0xa9, 0x45, 0xed, 0xfc, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xbf, 0xaa, 0xb5, 0xaa, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xbb, 0x9a, 0x3c, 0x04, 0xf4, 0x99, 0x6b, 0xf0, 0x7f, 0xa9, + 0xac, 0x54, 0x65, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, + 0x5f, 0xab, 0xaa, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0xda, 0x3f, 0xb0, 0x79, 0x48, + 0x17, 0xb8, 0xbf, 0xaa, 0x66, 0xab, 0xe6, 0xfe, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xfd, 0xbf, 0x55, 0x55, 0xab, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x6f, 0x5f, + 0xee, 0x1a, 0x1d, 0xc4, 0xfc, 0xff, 0xab, 0x29, 0xad, 0xa9, 0xf2, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x7f, 0x55, 0x55, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x8b, 0x6e, 0x77, 0x20, 0x1e, 0xc6, 0xf6, 0xd9, 0xaa, 0xa6, + 0xad, 0x6a, 0xa7, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xf3, + 0xff, 0xea, 0xbd, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x2b, 0x97, 0x2b, 0x5e, 0x6f, 0xe0, + 0x3e, 0x5d, 0x45, 0x4a, 0x56, 0x6d, 0xc5, 0xef, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xf7, 0xff, 0x8a, 0xa8, 0xad, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x6d, 0xeb, + 0x23, 0x50, 0x42, 0xf3, 0xd7, 0x96, 0x56, 0xa9, 0xb4, 0x52, 0xaa, 0xf7, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe7, 0xff, 0x6a, 0x57, 0x55, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0x67, 0x9b, 0xe5, 0x91, 0xad, 0x87, 0x78, 0xa1, 0xa2, 0x72, 0x25, + 0xad, 0x2a, 0xcb, 0xf7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xef, + 0xff, 0x2b, 0xa9, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x77, 0x7b, 0x4d, 0xe1, 0x49, 0xfb, + 0xaf, 0xde, 0xa4, 0x0a, 0x55, 0x95, 0xb5, 0xfb, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xcf, 0xff, 0xd5, 0xaa, 0x5a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xe8, 0xb9, + 0x4c, 0x6d, 0xe4, 0xbd, 0xd2, 0xe2, 0x96, 0xa3, 0x5a, 0xd5, 0xd4, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xdf, 0xff, 0xd7, 0xaa, 0xad, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0x4b, 0xe7, 0x8d, 0x8f, 0x79, 0xf2, 0xaf, 0x2a, 0x29, 0xaa, 0x13, + 0x4f, 0xa5, 0xea, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9f, + 0xff, 0x2b, 0xad, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0xfd, 0x72, 0xe4, 0x05, 0x7c, 0xf6, 0x55, + 0x55, 0xad, 0xb3, 0x48, 0x61, 0x6d, 0xf5, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x9f, 0xff, 0xb7, 0xaa, 0x6a, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x97, 0xff, 0x74, + 0xca, 0x6e, 0x76, 0xad, 0xaa, 0xaa, 0x6a, 0xb2, 0x5c, 0x59, 0xe9, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0xff, 0x57, 0xab, 0xad, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0xd9, 0xd5, 0x7e, 0x0c, 0x6e, 0xff, 0x07, 0xb0, 0xaa, 0x54, 0x29, 0x53, + 0xa5, 0x4a, 0xea, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, + 0xff, 0x5f, 0xa9, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6e, 0x3b, 0x90, 0xb5, 0xeb, 0x67, 0x54, + 0x5d, 0x55, 0x6d, 0xd5, 0x5a, 0xa9, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x3f, 0xff, 0x57, 0xdb, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x6f, 0xe7, 0xdf, 0xc9, + 0xd9, 0x79, 0x7b, 0x56, 0x4a, 0x95, 0xaa, 0x14, 0x2a, 0x55, 0xf5, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xdf, 0xaa, 0xd6, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0xb7, 0x9d, 0xfb, 0xc4, 0xdc, 0x7f, 0x7f, 0xaa, 0xaa, 0x6a, 0x25, 0x6d, + 0xab, 0x4a, 0xfa, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, + 0xfe, 0xbf, 0xda, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf7, 0xdd, 0xef, 0xff, 0x74, 0xde, 0xfb, 0x5f, 0xaa, + 0xaa, 0x56, 0x99, 0xaa, 0xaa, 0xaa, 0xfa, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x7f, 0xfe, 0x5f, 0x55, 0x6b, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xcf, 0xea, 0x6e, 0x66, + 0xff, 0xbb, 0x3f, 0x54, 0xad, 0xaa, 0x1a, 0x4d, 0xa5, 0x54, 0xfd, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0xfe, 0xbf, 0x6d, 0xad, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed, + 0xe7, 0xbf, 0x3f, 0xdb, 0xf7, 0xea, 0x0b, 0xa9, 0xaa, 0xaa, 0x5d, 0x75, + 0xad, 0x52, 0xfd, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xfe, 0xdf, 0x56, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xbf, 0x7f, 0x5f, 0xed, 0x1f, 0x8a, 0x3e, 0xbf, 0xce, 0xab, + 0x56, 0xb5, 0x4c, 0x95, 0x4a, 0x95, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xfc, 0x7f, 0xb5, 0xb5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0xe5, 0xe6, 0x0b, 0xf3, + 0xbf, 0xbe, 0x7f, 0xa9, 0xaa, 0xaa, 0x4e, 0x6b, 0x53, 0x52, 0xdf, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xfc, 0xbf, 0xd6, 0x56, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, + 0x5d, 0xf3, 0x07, 0xfa, 0x5b, 0x47, 0x57, 0xad, 0x5a, 0x75, 0x4a, 0x55, + 0x49, 0xa9, 0xde, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xfc, 0x7f, 0x6b, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xef, 0x7a, 0x4b, 0x7b, 0x01, 0xfd, 0x4d, 0xf2, 0x53, 0x55, + 0x57, 0x57, 0x61, 0x5b, 0xad, 0xac, 0xdf, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfc, 0xbf, 0xb5, 0x96, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0x01, 0xdb, + 0xae, 0xe5, 0x4a, 0x55, 0x55, 0xb5, 0xaf, 0xa5, 0xaa, 0x22, 0xdf, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0x5a, 0xfb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7d, 0x6f, + 0xf5, 0xbd, 0x40, 0xfc, 0x65, 0x35, 0x35, 0xcd, 0xaa, 0xd5, 0xa5, 0xba, + 0x4a, 0xaa, 0xdf, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xfc, 0x7f, 0x4d, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xbf, 0x57, 0xf6, 0x41, 0x57, 0x91, 0xca, 0x4a, 0xb5, + 0x56, 0x55, 0xaa, 0xcd, 0x5a, 0xd5, 0xdf, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfc, 0xff, 0x5a, 0xb7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xcf, 0x3e, 0x7f, 0x00, 0x60, + 0x57, 0x6b, 0x75, 0x55, 0xb5, 0xcb, 0xba, 0xd5, 0x2a, 0xc9, 0xdf, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x7f, 0xeb, 0xd5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, + 0x9f, 0x7f, 0x00, 0x68, 0x55, 0x54, 0x95, 0x5a, 0x55, 0xaa, 0x4a, 0x75, + 0x53, 0xd5, 0xdf, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xfe, 0xff, 0xad, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xef, 0x73, 0xc7, 0xb7, 0xd0, 0x5c, 0xdd, 0xa5, 0xaa, 0x6d, + 0xaa, 0x6a, 0xea, 0x56, 0x55, 0xf5, 0xdf, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xb5, 0xbe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfd, 0xed, 0xc7, 0x7d, 0x83, 0x8b, + 0x2e, 0xd5, 0xaa, 0x2a, 0xb5, 0x5a, 0x5d, 0xdb, 0x56, 0xf5, 0x9f, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x7f, 0xdb, 0xa5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xff, + 0xe3, 0x7f, 0x47, 0xd9, 0xa6, 0x6a, 0xab, 0xd6, 0xaa, 0x2a, 0x55, 0x55, + 0xaa, 0xe4, 0xbf, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0x7f, 0xad, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x37, 0xec, 0xff, 0xf2, 0xbf, 0x83, 0x96, 0x53, 0xa9, 0xaa, 0x55, + 0xad, 0x56, 0xad, 0xd5, 0x55, 0xeb, 0x3f, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0xfc, 0x7f, 0x6b, 0xad, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3e, 0x6d, 0xfb, 0xce, 0xe1, 0x52, + 0x59, 0xad, 0xaa, 0x9a, 0xaa, 0x5a, 0x6b, 0x5d, 0xaa, 0xea, 0x3f, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x7f, 0x5d, 0xeb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x3f, 0xfb, + 0xff, 0xf3, 0x51, 0xcd, 0x56, 0x55, 0xd5, 0x6a, 0xb5, 0x56, 0xb5, 0x56, + 0xab, 0xea, 0x7f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xe7, 0xff, 0xd6, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x4f, 0xcf, 0xcf, 0xdd, 0xe7, 0x58, 0x62, 0x52, 0xd5, 0xb6, 0x96, + 0xaa, 0x55, 0xad, 0x69, 0x55, 0xfb, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x6b, 0x6b, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x8b, 0xef, 0xc7, 0x7f, 0x21, 0xc4, 0x96, + 0xad, 0xaa, 0xaa, 0x6a, 0xad, 0xaa, 0x56, 0xaf, 0x31, 0xf5, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0xb5, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xfb, 0xf3, + 0xdd, 0x61, 0xee, 0xd4, 0x56, 0x6d, 0xd5, 0x2a, 0xb5, 0xd6, 0xda, 0xaa, + 0x9c, 0x75, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xae, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe3, 0xab, 0x7b, 0x7f, 0x20, 0xfa, 0x41, 0xd5, 0x52, 0x55, 0xd5, + 0x56, 0x55, 0x6b, 0x55, 0x6b, 0x15, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xbf, 0xf5, 0xb5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbf, 0xe1, 0xf6, 0xff, 0x4f, 0x20, 0xac, 0xb4, + 0xaa, 0xb6, 0x6d, 0x55, 0x55, 0xab, 0xad, 0xad, 0x34, 0x15, 0xc0, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xbf, 0x56, 0xd5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x63, 0xfb, 0xda, + 0x37, 0x40, 0x2a, 0xab, 0xb5, 0x5a, 0xb5, 0x55, 0xb5, 0x6a, 0x55, 0x55, + 0xab, 0x15, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xff, + 0xff, 0x4f, 0xdb, 0x6e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xf3, 0xfc, 0xff, 0x11, 0x52, 0x55, 0x69, 0xad, 0xaa, 0x96, 0xaa, + 0xd6, 0xaa, 0x76, 0x5d, 0x55, 0x0d, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0xff, 0xff, 0x87, 0x55, 0xab, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf3, 0x7e, 0xff, 0x19, 0xd2, 0xd1, 0xb5, + 0x55, 0x55, 0xab, 0xaa, 0xaa, 0xb5, 0x55, 0x53, 0xb5, 0x0a, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0x87, 0xfa, 0xed, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x38, 0xff, 0xef, + 0x9e, 0xad, 0xd4, 0x54, 0xd5, 0x76, 0x6d, 0x55, 0x75, 0xd5, 0x56, 0x6d, + 0x95, 0x0d, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, + 0xff, 0x83, 0x2f, 0x35, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0xdc, 0xbf, 0xff, 0x01, 0x42, 0xae, 0x5b, 0x6d, 0x55, 0xab, 0x52, + 0x55, 0xb5, 0xda, 0x96, 0xca, 0x0e, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0xfe, 0xff, 0x81, 0xd5, 0xda, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3d, 0xfe, 0xfb, 0x7b, 0x4d, 0x03, 0xb5, 0xd2, + 0x55, 0xab, 0x55, 0x55, 0xad, 0xda, 0x56, 0xb3, 0x5a, 0x0d, 0x00, 0xf8, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xfc, 0xff, 0x80, 0x6d, 0xd7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe8, 0xdf, 0xef, + 0xa7, 0x9d, 0xd4, 0x6d, 0xaa, 0xda, 0xaa, 0xaa, 0xd5, 0x56, 0xab, 0xdc, + 0xd6, 0x0e, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xf8, + 0x7f, 0x80, 0xb6, 0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8e, 0xfd, 0xfe, 0xff, 0xd1, 0xdd, 0x75, 0x55, 0xd9, 0x6a, 0x6d, 0x55, + 0x6d, 0x75, 0xb5, 0xa5, 0xab, 0x07, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0xf0, 0x1f, 0x80, 0xdb, 0xb5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x4f, 0xf6, 0xff, 0x7d, 0x28, 0xb7, 0x2a, 0xb5, + 0x6a, 0xad, 0xaa, 0x5a, 0xb5, 0x56, 0xab, 0xba, 0xea, 0x07, 0x00, 0xe0, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xe0, 0x07, 0x80, 0xb5, 0xae, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x23, 0x7e, 0xef, 0x5f, + 0x38, 0x57, 0x5a, 0x93, 0x56, 0xad, 0xad, 0xaa, 0x5d, 0xab, 0xba, 0xca, + 0xff, 0x03, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x80, 0xdf, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xb2, 0xff, 0xff, 0xfe, 0xe8, 0xb5, 0xca, 0xea, 0xda, 0xb6, 0x6a, 0xad, + 0x56, 0x75, 0x4b, 0xf5, 0x78, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x6b, 0x5f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xdf, 0xff, 0x53, 0xf7, 0x6f, 0x6a, 0xad, 0xaa, 0xaa, + 0x6a, 0xd5, 0x56, 0xab, 0xda, 0xae, 0x6a, 0x3d, 0x00, 0x00, 0x00, 0x80, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0xb7, 0x6a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8b, 0x7f, 0x3f, + 0xd3, 0x5a, 0x67, 0x5b, 0x55, 0x55, 0x55, 0x55, 0x57, 0x55, 0x5d, 0x35, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x80, 0xdf, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0x6d, 0xc3, 0xff, 0xd3, 0x51, 0xad, 0xba, 0xaa, 0xb6, 0xb6, 0xb6, 0xd5, + 0xb5, 0xd5, 0x66, 0x35, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd7, 0xd6, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xbf, 0xff, 0xe1, 0xb7, 0xc0, 0xaa, 0xb6, 0x4b, 0xd5, + 0xda, 0x5a, 0xab, 0xb6, 0xd6, 0xb6, 0xba, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7f, 0x75, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x97, 0xf0, 0xfe, 0x71, + 0x5c, 0xab, 0x59, 0x5b, 0x55, 0xad, 0xb5, 0xaa, 0x75, 0xb5, 0x56, 0x7b, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x7e, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, + 0x8e, 0xfa, 0xff, 0x32, 0xd6, 0xda, 0x6a, 0x55, 0x5d, 0xd5, 0x5a, 0x5b, + 0x5b, 0xab, 0x59, 0x7d, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfe, 0xad, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfa, 0x0f, 0xbd, 0x37, 0x9d, 0xd6, 0xd6, 0x5a, 0xad, + 0xd5, 0xb6, 0xee, 0xea, 0x6d, 0x55, 0xad, 0x75, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcd, 0x4b, 0xff, 0x1e, 0x95, + 0x2d, 0xab, 0x66, 0x55, 0xad, 0xaa, 0x55, 0xad, 0xb6, 0xba, 0xd5, 0xea, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x40, 0x0e, 0x00, + 0x00, 0x00, 0x80, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xee, + 0xe7, 0xdf, 0x07, 0x77, 0x75, 0x75, 0x2f, 0xd5, 0xd6, 0x5a, 0xb5, 0xb6, + 0x55, 0xd5, 0x56, 0xfb, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, + 0x00, 0x60, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x77, 0xf8, 0xe3, 0x7f, 0x83, 0x4d, 0xaf, 0x55, 0xa5, 0x55, + 0x55, 0xad, 0x5b, 0xdb, 0x7e, 0x5b, 0x6b, 0xed, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x07, 0x00, 0x00, 0x00, 0xf0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xbc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfe, 0xf0, 0xf6, 0x81, 0xd4, + 0xe9, 0xb6, 0xaa, 0xd5, 0xb6, 0xb6, 0x6a, 0x55, 0x8b, 0xaa, 0xba, 0xe5, + 0x01, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xdf, + 0xfd, 0xff, 0x6d, 0xb8, 0xae, 0x6a, 0xd5, 0x56, 0xab, 0xd5, 0xad, 0xed, + 0x76, 0x75, 0xab, 0xec, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x8b, 0xff, 0xff, 0x3f, 0x61, 0xad, 0x6a, 0x5d, 0x6d, 0xd5, + 0xda, 0x6e, 0x6d, 0xb5, 0xae, 0x5e, 0xad, 0xe6, 0x01, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0xfe, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xdc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xed, 0xdd, 0x76, 0x59, 0x55, + 0xad, 0xd5, 0x96, 0x5e, 0x55, 0xb5, 0xaa, 0xae, 0xa7, 0xaa, 0x65, 0xf3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x7f, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0xbe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb, 0xff, + 0xff, 0xbf, 0x3c, 0xf5, 0x6b, 0x6d, 0x4b, 0x53, 0xdb, 0xd5, 0x6e, 0xb3, + 0xb5, 0x76, 0x6d, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, + 0xc0, 0x7f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfb, 0xef, 0xfe, 0xff, 0x1e, 0x2d, 0xbd, 0x56, 0xab, 0xad, + 0xad, 0x6e, 0xb5, 0xdd, 0x5d, 0x5b, 0x55, 0xf7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe6, 0x01, 0x00, 0xf0, 0x7f, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0x6f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfd, 0xfd, 0x77, 0x57, 0xa9, 0xb6, + 0x4d, 0x6b, 0xad, 0xaa, 0xda, 0xaa, 0x55, 0xd5, 0xa6, 0xd1, 0xdd, 0x72, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x07, 0x00, 0xff, 0x7f, 0x0f, 0x00, + 0x00, 0x00, 0xf0, 0x6b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, + 0xfe, 0x7f, 0xed, 0xd5, 0xd6, 0x9a, 0x6a, 0xb5, 0x5d, 0xdb, 0xde, 0xb6, + 0xda, 0x5e, 0xab, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xff, 0xff, + 0xff, 0x7f, 0x07, 0x00, 0x00, 0x00, 0xfc, 0xb6, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x77, 0xff, 0x6f, 0xbf, 0x3f, 0x35, 0x57, 0xab, 0x6d, 0xad, 0x5a, + 0x6d, 0x6b, 0x6b, 0xdb, 0xab, 0x54, 0xd5, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9c, 0xff, 0xff, 0xff, 0x3f, 0x07, 0x00, 0x00, 0x80, 0x7f, 0xdb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xbf, 0xfb, 0x9b, 0xd4, 0xba, + 0x6d, 0x52, 0x57, 0xad, 0xb5, 0x6a, 0xad, 0xb6, 0x5a, 0xb7, 0xb5, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xff, 0xff, 0xff, 0x3f, 0x07, 0x00, + 0x00, 0xf0, 0xd7, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xdd, + 0xff, 0xcf, 0xdc, 0xda, 0xea, 0x5b, 0xab, 0xaa, 0xde, 0x5d, 0xeb, 0xda, + 0xea, 0x5a, 0xad, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0xff, + 0xff, 0x9f, 0x07, 0x00, 0x00, 0xfc, 0x5b, 0xdb, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf7, 0xfe, 0xb7, 0x7f, 0x77, 0xb7, 0xae, 0x56, 0x6d, 0x55, 0x6d, + 0xab, 0xaa, 0x5d, 0xaf, 0xad, 0xd6, 0xaa, 0xf6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbc, 0xff, 0xff, 0xff, 0x9f, 0x07, 0x00, 0x00, 0xbf, 0xed, 0xb6, + 0xff, 0xff, 0xff, 0xff, 0xbf, 0x7f, 0xef, 0xff, 0xbb, 0x7f, 0xdb, 0x56, + 0x7b, 0x55, 0x55, 0xab, 0xd5, 0xb6, 0xd6, 0xea, 0x6a, 0xab, 0xb6, 0xea, + 0x07, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xff, 0xff, 0xff, 0x9f, 0x0f, 0x00, + 0x80, 0xbf, 0x6d, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x7f, 0xfd, + 0xff, 0xdc, 0x6e, 0x77, 0xd5, 0x56, 0x6b, 0x6d, 0x6d, 0xdb, 0x6b, 0xb7, + 0xb6, 0x5a, 0x55, 0xeb, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xff, 0xff, + 0xff, 0xbf, 0x0f, 0x00, 0xc0, 0xd7, 0xb6, 0x6d, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xbd, 0x9f, 0xdd, 0x5d, 0xef, 0xb6, 0xdb, 0x56, 0xaa, 0x5a, 0xb5, + 0xb6, 0x55, 0xbd, 0xb5, 0xaa, 0xad, 0x6d, 0xad, 0xfe, 0x0f, 0x00, 0x00, + 0x00, 0xde, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xf0, 0xdf, 0xb6, 0x6d, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xab, 0xfe, 0x7f, 0x56, 0xab, 0xae, + 0xfa, 0x56, 0xab, 0x56, 0xd5, 0xda, 0xd5, 0xde, 0xdd, 0x56, 0x55, 0x6b, + 0xd5, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, + 0xf8, 0x6b, 0xdb, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xdf, 0x3f, 0x3f, + 0xbd, 0xb7, 0xb5, 0xab, 0x57, 0x55, 0xd5, 0xea, 0xb6, 0x6a, 0x6d, 0x6b, + 0xd5, 0xaa, 0xb6, 0xb5, 0x5a, 0xfd, 0x1f, 0x00, 0x00, 0xff, 0x57, 0xf5, + 0xb6, 0xdd, 0x1f, 0x00, 0xfc, 0xb5, 0xd5, 0xaa, 0xff, 0xff, 0xff, 0xff, + 0xde, 0xbf, 0x9e, 0x3f, 0xef, 0x7d, 0xed, 0xd6, 0x5a, 0xb5, 0xaa, 0xae, + 0x6d, 0xb5, 0xb6, 0x5d, 0x6d, 0x55, 0xab, 0xaa, 0xd6, 0x96, 0xff, 0x01, + 0x80, 0x7f, 0x55, 0x2b, 0x5b, 0xf5, 0x3f, 0x00, 0xff, 0xda, 0x76, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xee, 0xcb, 0xe7, 0xd7, 0xaf, 0xaa, 0xb6, 0x55, + 0x6d, 0x55, 0xad, 0x6a, 0xb5, 0xdd, 0xb6, 0xd6, 0xb6, 0xb6, 0xac, 0xad, + 0x55, 0x1b, 0xfa, 0x0f, 0xe0, 0x5f, 0x53, 0x6d, 0xe9, 0x76, 0xff, 0xe0, + 0xdf, 0x56, 0x5b, 0x6b, 0xff, 0xff, 0xff, 0x7f, 0xef, 0xdf, 0xe7, 0xff, + 0xef, 0xdf, 0x6d, 0xef, 0x55, 0xad, 0x6a, 0xb7, 0x56, 0x55, 0x6d, 0xbb, + 0x59, 0xab, 0xa5, 0xb6, 0x6a, 0x6d, 0xd5, 0xff, 0xf8, 0xdb, 0xb2, 0x55, + 0x57, 0xcd, 0xff, 0xff, 0xbf, 0xed, 0xb5, 0xb5, 0xff, 0xff, 0xff, 0xbf, + 0x7b, 0x6f, 0xf5, 0x7e, 0x75, 0x69, 0xed, 0xb5, 0xb6, 0xd6, 0xaa, 0xd5, + 0x5b, 0xd5, 0xb6, 0xad, 0x6e, 0xd5, 0xbe, 0xaa, 0xad, 0x35, 0x55, 0xff, + 0xff, 0x6d, 0x59, 0xb5, 0x75, 0xb7, 0xfe, 0xff, 0xd7, 0xb6, 0xb6, 0xbd, + 0xff, 0xff, 0xff, 0x7f, 0xff, 0xfb, 0xf5, 0xdb, 0xab, 0x56, 0x5b, 0x6b, + 0xad, 0x52, 0xed, 0x5a, 0xb5, 0x6d, 0xdb, 0xd6, 0xaa, 0x2a, 0x57, 0xdb, + 0xb6, 0x5a, 0xd5, 0xfd, 0xff, 0xaa, 0x52, 0x5b, 0xad, 0xda, 0xfe, 0xff, + 0x7b, 0xdb, 0xea, 0xd6, 0xff, 0xff, 0xff, 0xaf, 0xdd, 0xbf, 0x72, 0x7f, + 0xdb, 0xfe, 0xed, 0xba, 0x55, 0x55, 0xb5, 0xae, 0xd6, 0xaa, 0x6d, 0xbb, + 0xae, 0x6d, 0x6d, 0x55, 0xad, 0x75, 0x5b, 0xed, 0xbf, 0xea, 0xa9, 0x69, + 0xb7, 0x6b, 0xf5, 0xff, 0x55, 0xdb, 0x7e, 0xdb, 0xff, 0xff, 0xff, 0x3b, + 0xfe, 0xf6, 0xf1, 0xd7, 0xbe, 0x55, 0xbb, 0xae, 0x6a, 0xd7, 0xaa, 0x6a, + 0x5b, 0x75, 0xab, 0x55, 0x7b, 0x55, 0x55, 0xb7, 0x55, 0xb3, 0xaa, 0xd6, + 0x5a, 0x55, 0xa5, 0xb6, 0xd5, 0x5a, 0xb5, 0xdb, 0xba, 0x6d, 0xab, 0xb6, + 0xff, 0xff, 0xff, 0x8f, 0xef, 0xff, 0xb8, 0xfa, 0xdf, 0xd5, 0xde, 0xb5, + 0xad, 0xda, 0xaa, 0xab, 0x6a, 0x5b, 0x5d, 0xbd, 0x8a, 0xb6, 0xdd, 0xda, + 0x76, 0xdb, 0xaa, 0xaa, 0xaa, 0x76, 0x55, 0x55, 0x75, 0x55, 0xd5, 0x6a, + 0xd7, 0xb6, 0x6d, 0xdb, 0xff, 0xff, 0xff, 0xdb, 0x7f, 0xbe, 0xf1, 0x6f, + 0xab, 0x7d, 0xab, 0x6e, 0xd7, 0x6d, 0x6b, 0xb5, 0xad, 0xaa, 0xab, 0x57, + 0xb7, 0xaa, 0x6a, 0xab, 0xaa, 0xa2, 0xda, 0xd6, 0x56, 0x55, 0xa5, 0x6d, + 0x5b, 0xfb, 0x6d, 0xbb, 0x5a, 0xdb, 0xb6, 0xb6, 0xff, 0xff, 0x7f, 0xcf, + 0x36, 0xf7, 0xb8, 0x77, 0xff, 0xd6, 0xbb, 0xb5, 0x69, 0x35, 0xb5, 0x5d, + 0x6d, 0xbb, 0xda, 0xad, 0x55, 0x6b, 0xab, 0xda, 0xb5, 0xbd, 0xaa, 0x5a, + 0xb5, 0xea, 0xaa, 0x55, 0xad, 0x2a, 0x6a, 0xad, 0xd5, 0x6d, 0xb3, 0xdb }; diff --git a/arch/m68knommu/platform/68VZ328/xbm2lcd.pl b/arch/m68knommu/platform/68VZ328/xbm2lcd.pl new file mode 100644 index 00000000..f00d9233 --- /dev/null +++ b/arch/m68knommu/platform/68VZ328/xbm2lcd.pl @@ -0,0 +1,6 @@ + +$_ = join("", <>); + +s/(0x[0-9a-f]{2})/sprintf("0x%.2x",ord(pack("b8",unpack("B8",chr(~hex($1)&0377)))))/gei; + +print $_; diff --git a/arch/nios2nommu/ChangeLog b/arch/nios2nommu/ChangeLog new file mode 100644 index 00000000..039c0108 --- /dev/null +++ b/arch/nios2nommu/ChangeLog @@ -0,0 +1,4 @@ +2004-06-15 Ken Hill + + * Kconfig: Add Microtronix uKit support. + diff --git a/arch/nios2nommu/Kconfig b/arch/nios2nommu/Kconfig new file mode 100644 index 00000000..8e87a114 --- /dev/null +++ b/arch/nios2nommu/Kconfig @@ -0,0 +1,397 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu 'uClinux/Nios2 (w/o MMU) Kernel Configuration' + +config MMU + bool + default n + +config FPU + bool + default n + +config UID16 + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +config GENERIC_FIND_NEXT_BIT + bool + default y + +config GENERIC_HWEIGHT + bool + default y + +config GENERIC_CALIBRATE_DELAY + bool + default y + +source "init/Kconfig" + +menu "Processor type and features" + +comment 'Platform dependant setup' + +choice + prompt "CPU" + default NIOS2 + +config NIOS2 + bool "NIOS2" + help + Altera Nios2 softcore processor. + +endchoice + +choice + prompt "Platform" + default ALTERA_STRATIX + +config MICROTRONIX_UKIT + bool "Microtronix uKit board support" + depends on NIOS2 + help + Support for the Microtronix uKit development board. Includes support + for Sodimm SDRAM/FLASH, soft ethernet MAC & PHY. + +config MICROTRONIX_STRATIX + bool "Microtronix Stratix board support" + depends on NIOS2 + help + Support for the Microtronix Stratix board. Includes support + for Sodimm SDRAM/FLASH, soft ethernet MAC & PHY, USB, LVDS + & analog/digital converters. + +config MICROTRONIX_CYCLONE + bool "Microtronix Cyclone board support" + depends on NIOS2 + help + Support for the Microtronix Cyclone board. Includes support + for SDRAM, FLASH, soft ethernet MAC & PHY, USB, + & analog/digital converters. + +config MICROTRONIX_PSK + bool "Microtronix PSK (Product Starter Kit) support" + depends on NIOS2 + help + Support for the Microtronix PSK (Product Starter Kit), which + features firefly module (EP1C4 or EP1C12). Includes support + for SDRAM, FLASH, and a variety of product expansion kits such + as USB, Ethernet etc. + +config ALTERA_STRATIX + bool "Altera Stratix Development board support" + depends on NIOS2 + help + Support for the Altera Stratix Development board. Includes + support for 10/100 ethernet, FLASH, SDRAM, compact flash. + +config ALTERA_STRATIX_PRO + bool "Altera Stratix Pro Development board support" + depends on NIOS2 + help + Support for the Altera Stratix 1s40 Development board. Includes + support for 10/100 ethernet, FLASH, SDRAM, compact flash. + +config ALTERA_STRATIX_II + bool "Altera Stratix II Development board support" + depends on NIOS2 + help + Support for the Altera Stratix II Development board. Includes + support for 10/100 ethernet, FLASH, SDRAM, compact flash. + +config ALTERA_CYCLONE + bool "Altera Cyclone Development board support" + depends on NIOS2 + help + Support for the Altera Cyclone Development board. Includes + support for 10/100 ethernet, FLASH, SDRAM, compact flash. + +config ALTERA_CYCLONE_1C12_EVAL + bool "Altera Cyclone 1C12 Evaluation board support" + depends on NIOS2 + help + Support for the Altera Cyclone 1C12 Evaluation board (with the + embedded processor module). + +config ALTERA_DE2 + bool "Altera DE2 Development board support" + depends on NIOS2 + help + Support for the Altera Cyclone Development board. Includes + support for 10/100 ethernet, FLASH, SDRAM, VGA, I2C. + +endchoice + +choice + prompt "Nios II Hardware Multiply Support" + default NIOS2_HW_MULX + help + This option enables various assembler instructions based on your + selection. The choice depends on what target hardware you'll be + running your applications on. The default is + "Enable mulx instruction". + + Here is an explanation of each option: + None = -mno-hw-mul -mno-hw-mulx + (no mul or mulx instructions used) + Enable mul instruction = -mhw-mul -mno-hw-mulx + (use mul instructions) + Enable mul and mulx instructions = -mhw-mul -mhw-mulx + (use mul and mulx instructions) + + If you don't know what to choose, select "Enable mulx instruction". + +config NIOS2_HW_MUL_OFF + bool "None" + +config NIOS2_HW_MUL + bool "Enable mul instruction" + +config NIOS2_HW_MULX + bool "Enable mul and mulx instructions" + +endchoice + +comment 'Platform drivers Options' + +config AVALON_DMA + bool "Support of DMA controller with Avalon interface" + default y + help + This enables support of Altera's DMA controller with Avalon + interface, so that drivers of DMA-able device can use this + interface. + +config PIO_DEVICES + bool "Enable leds, seven segment display" + default y + depends on (ALTERA_STRATIX || ALTERA_STRATIX_PRO || ALTERA_CYCLONE) + help + This enables example code to support leds, and seven segment + display as PIO devices. Once enabled, the kernel will show a + counter (increas once a second) on these devices. + +source "arch/nios2nommu/drivers/Kconfig" + +comment 'Miscellaneous Options' + +config EXCALIBUR + bool + default y + depends on (NIOS2) + +config BREAK_ON_START + bool "Include breakpoint trap on kernel startup" + help + Configures the kernel to trap to the GDB client on startup + before the kernel starts initialization. This allows you to + debug the kernel startup. + +config LARGE_ALLOCS + bool "Allow allocating large blocks (> 1MB) of memory" + help + Allow the slab memory allocator to keep chains for very large + memory sizes - upto 32MB. You may need this if your system has + a lot of RAM, and you need to able to allocate very large + contiguous chunks. If unsure, say N. + +choice + prompt "Kernel executes from" + ---help--- + Choose the memory type that the kernel will be running in. + +config RAMKERNEL + bool "RAM" + help + The kernel will be resident in RAM when running. + +#config ROMKERNEL +# bool "ROM" +# help +# The kernel will be resident in FLASH/ROM when running. + +#config HIMEMKERNEL +# bool "HIMEM" +# help +# The kernel will be resident in high memory when running. + +endchoice + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +config PREEMPT_TIMES + bool "Collect preemption latency times" + depends on PREEMPT + help + Allow collection for preemption latency times. + +config CMDLINE + string "Default kernel command string" + default "CONSOLE=/dev/ttyS0 root=/dev/rom0 ro" + help + On some architectures, there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (e.g., mem=64M root=/dev/nfs). + +config PASS_CMDLINE + bool "Passed kernel command line from u-boot" + default n + help + Use bootargs env variable from u-boot for kernel command line. + will override "Default kernel command string". + Say N if you are unsure. + +source "mm/Kconfig" + +config BOOT_LINK_OFFSET + hex "Link address offset for booting" + default "0x00800000" + help + This option allows you to set the link address offset of the zImage. + This can be useful if you are on a board which has a small amount of + memory. + +endmenu + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config PCI + bool "PCI support" + help + Support for PCI bus. + +source "drivers/pci/Kconfig" + +config HOTPLUG + bool "Support for hot-pluggable device" + ---help--- + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at ) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +config KCORE_AOUT + bool + default y + +config KCORE_ELF + bool + default y + +source "fs/Kconfig.binfmt" + +endmenu + +menu "Power management options" + +config PM + bool "Power Management support" + help + Support processor power management modes + +endmenu + + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +menu "Kernel hacking" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + help + Enables console device to interpret special characters as + commands to dump state information. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + depends on COLDFIRE + help + Use a fast secondary clock to produce profiling information. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config LOG_BUF_SHIFT + int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL + range 12 21 + default 17 if ARCH_S390 + default 16 if X86_NUMAQ || IA64 + default 15 if SMP + default 14 + help + Select kernel log buffer size as a power of 2. + Defaults and Examples: + 17 => 128 KB for S/390 + 16 => 64 KB for x86 NUMAQ or IA-64 + 15 => 32 KB for SMP + 14 => 16 KB for uniprocessor + 13 => 8 KB + 12 => 4 KB + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" diff --git a/arch/nios2nommu/Kconfig.debug b/arch/nios2nommu/Kconfig.debug new file mode 100644 index 00000000..b188c4a1 --- /dev/null +++ b/arch/nios2nommu/Kconfig.debug @@ -0,0 +1,35 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config FRAME_POINTER + bool "Compile the kernel with frame pointers" + help + If you say Y here the resulting kernel image will be slightly larger + and slower, but it will give very useful debugging information. + If you don't debug the kernel, you can say N, but we may not be able + to solve problems without frame pointers. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + help + Enables console device to interpret special characters as + commands to dump state information. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + depends on COLDFIRE + help + Use a fast secondary clock to produce profiling information. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +endmenu diff --git a/arch/nios2nommu/Makefile b/arch/nios2nommu/Makefile new file mode 100644 index 00000000..4c94558a --- /dev/null +++ b/arch/nios2nommu/Makefile @@ -0,0 +1,181 @@ +# arch/niosnommu/Makefile +# +# Makefile for the architecture dependent flags and dependencies on the +# nios. +# +# Copyright (C) 2001 Vic Phillips (vic@microtronix.com) +# +# based on sparcnommu/Makefile: +# +# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) +# +KERNELLOAD = ${shell echo `grep "nasys_program_mem " include/asm/nios.h | sed 's/^.*\*)//' | sed 's/)//'`} + +HARDWARE_MK = arch/$(ARCH)/hardware.mk + +platform-$(CONFIG_NIOS) := NIOS2 +PLATFORM := $(platform-y) + +board-$(CONFIG_ALTERA_STRATIX) := altera_stratix +board-$(CONFIG_ALTERA_STRATIX_PRO) := altera_stratix_pro +board-$(CONFIG_ALTERA_STRATIX_II) := altera_stratix_ii +board-$(CONFIG_ALTERA_CYCLONE) := altera_cyclone +board-$(CONFIG_ALTERA_CYCLONE_1C12_EVAL) := altera_cyclone_1c12_eval +board-$(CONFIG_MICROTRONIX_STRATIX) := microtronix_stratix +board-$(CONFIG_MICROTRONIX_CYCLONE) := microtronix_cyclone +board-$(CONFIG_MICROTRONIX_UKIT) := microtronix_ukit +board-$(CONFIG_MICROTRONIX_PSK) := microtronix_psk +BOARD := $(board-y) + +model-$(CONFIG_RAMKERNEL) := ram +model-$(CONFIG_ROMKERNEL) := rom +model-$(CONFIG_HIMEMKERNEL) := himem +MODEL := $(model-y) + +export PLATFORM BOARD MODEL + +CFLAGS += -DNO_MM -pipe -D__linux__ -D__ELF__ +#CFLAGS += -DNO_MM -save-temps -D__linux__ -D__ELF__ + +# Uncomment this if you are doing gdb source level +# debugging of the kernel to get the proper debugging information. +# +#CFLAGS += -DDEBUG + +# Turn on/off various hardware multiply options +cpu-cflags-$(CONFIG_NIOS2_HW_MUL_OFF) += -mno-hw-mul -mno-hw-mulx +cpu-cflags-$(CONFIG_NIOS2_HW_MUL) += -mhw-mul -mno-hw-mulx +cpu-cflags-$(CONFIG_NIOS2_HW_MULX) += -mhw-mul -mhw-mulx +CFLAGS += $(cpu-cflags-y) + +# mulx flags currently cause older version of nios2-elf-gcc to fail +# The following line ensures that all mulx flags are removed before +# it is passed to the compiler. +mulx_help_text:= $(shell $(CC) --target-help | grep mulx) +ifeq "$(mulx_help_text)" "" +CFLAGS := $(filter-out -mhw-mulx -mno-hw-mulx, $(CFLAGS)) +endif + +# Temporary workaround for nios2-elf-gcc bug +# First noticed in v3.4.1 (Altera Nios II 1.1 b131) +# To be removed at a later date when bug is resolved. +CFLAGS += -fno-optimize-sibling-calls + +# This undefines the "__init" type used in defining initialization +# procedures. When defined, the procedures are put into an 'init' data +# section that GDB doesn't recognize as source. +# +CFLAGS += -DNO_TEXT_SECTIONS +CFLAGS += -fno-builtin +CFLAGS += -O2 -g -G 0 +CFLAGS += -DUTS_SYSNAME=\"uClinux\" + +CFLAGS_GCC_INC := $(shell $(CC) -print-file-name=include) +CFLAGS += -I$(CFLAGS_GCC_INC) + +AFLAGS += -DNO_MM -g +#AFLAGS += -DNO_MM -g -save-temps + +# vic - add this to get name of nios gcc library +LIBGCC_CFLAGS = $(if $(CONFIG_NIOS2_HW_MUL_OFF),-mno-hw-mul) +LIBGCC := `$(CC) --print-libgcc-file-name $(LIBGCC_CFLAGS)` + +# add this to avoid multiple '_stack' and '_vecbase' definition errors +# +ifdef niosgnu +# Include the path to the lib directory where the ldscripts are found to fix +# a problem with the cygwin/bash environment. + +#cygwhack: kenw - this following section could be a possible problem +# due to the O= option on the command line. +LDSCRIPTS:=$(shell nios2-elf-gcc -print-file-name=ldscripts) +LDFLAGS += -mnios2elf -L $(LDSCRIPTS)/.. +else +LDFLAGS += -mnios2elf +LDLIBS := -L `$(CC) -print-file-name=m32` -l gcc +endif + +head-y := arch/nios2nommu/kernel/head.o arch/nios2nommu/kernel/init_task.o + +CLEAN_FILES := include/asm-$(ARCH)/asm-offsets.h \ + $(HARDWARE_MK) \ + arch/$(ARCH)/kernel/asm-offsets.s \ + linux.srec \ + linux.flash \ + linux.bin \ + linux.bin.srec + +core-y += arch/nios2nommu/kernel/ \ + arch/nios2nommu/mm/ \ + arch/nios2nommu/drivers/ + +libs-y += arch/nios2nommu/lib/ + +libs-y += $(LIBGCC) +####;dgt2;tmp; + +# force user to configure hardware before building kernel + +pardoned_targets = clean mrproper sgmldocs psdocs pdfdocs \ + htmldocs mandocs + +-include $(HARDWARE_MK) +build_targets = $(filter-out $(pardoned_targets), $(MAKECMDGOALS)) +ifneq '$(strip $(build_targets))' '' + ifndef SYSPTF + ifneq '$(firstword $(MAKECMDGOALS))' 'hwselect' + $(error Run "make hwselect SYSPTF=" first) + endif + endif +endif + +quiet_cmd_gen_mk = ' RUNNING $@' +define cmd_gen_mk + mkdir -p $(dir $(objtree)/$(HARDWARE_MK)); \ + perl -I$(TOPDIR)/arch/$(ARCH)/scripts \ + $(srctree)/arch/$(ARCH)/scripts/hwselect.pl $(SYSPTF) \ + $(objtree)/$(HARDWARE_MK) +endef + +.PHONY: hwselect +hwselect: + @echo $($(quiet)cmd_gen_mk); + @$(cmd_gen_mk) + +prepare: include/nios2_system.h + +archclean: + $(call descend arch/$(ARCH)/boot, subdirclean) + +define filechk_nios2_system.h + # call perl script that will build nios2_system.h file + perl -I$(TOPDIR)/arch/$(ARCH)/scripts \ + $(TOPDIR)/arch/$(ARCH)/scripts/gen_nios2_system.h.pl $(CPU) $(EXEMEM) $(UPLMEM) +endef + +include/nios2_system.h: $(SYSPTF) FORCE + $(call filechk,nios2_system.h) + +quiet_cmd_touch = ' TOUCH $@' + cmd_touch = touch $(TOPDIR)/$@ + +arch/$(ARCH)/kernel/vmlinux.lds.S: FORCE + @echo $($(quiet)cmd_touch); + @$(cmd_touch) + +linuxsrec: linux + $(OBJCOPY) -O srec $(LINUX) linux.srec + +boot := arch/nios2nommu/boot + +zImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +compressed: zImage + +CLEAN_FILES += include/nios2_system.h + +archmrproper: + +archdep: + diff --git a/arch/nios2nommu/boot/Makefile b/arch/nios2nommu/boot/Makefile new file mode 100644 index 00000000..fd25b72e --- /dev/null +++ b/arch/nios2nommu/boot/Makefile @@ -0,0 +1,17 @@ +# +# arch/nios2nommu/boot/Makefile +# +# 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. + +targets := zImage +subdir- := compressed + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + diff --git a/arch/nios2nommu/boot/compressed/Makefile b/arch/nios2nommu/boot/compressed/Makefile new file mode 100644 index 00000000..2002471c --- /dev/null +++ b/arch/nios2nommu/boot/compressed/Makefile @@ -0,0 +1,36 @@ +# +# linux/arch/sh/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \ + piggy.o vmlinux.lds +EXTRA_AFLAGS := + +OBJECTS = $(obj)/head.o $(obj)/misc.o + +# +# IMAGE_OFFSET is the load offset of the compression loader +# +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000]) +#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000]) + +LDFLAGS_vmlinux := -T + +$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-littlenios2 -T + +OBJCOPYFLAGS += -O binary + +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff --git a/arch/nios2nommu/boot/compressed/head.S b/arch/nios2nommu/boot/compressed/head.S new file mode 100644 index 00000000..accadd0f --- /dev/null +++ b/arch/nios2nommu/boot/compressed/head.S @@ -0,0 +1,100 @@ +/* + * linux/arch/nios2nommu/boot/compressed/head.S + * + */ + + .text + .set noat +#include +#include + + /* + * This code can be loaded anywhere, as long as output will not + * overlap it. + * + */ + + .global _start +_start: + // disable interrupt + wrctl status, r0 + // flush the instruction cache + movia r1,NIOS2_ICACHE_SIZE + movi r2,NIOS2_ICACHE_LINE_SIZE +text_init: + initi r1 + sub r1, r1, r2 + bgt r1, zero, text_init + // then flush the pipeline + flushp + // flush the data cache + movia r1,NIOS2_DCACHE_SIZE + movi r2,NIOS2_DCACHE_LINE_SIZE +data_init: + initd (r1) + sub r1, r1, r2 + bgt r1, zero, data_init + //------------------------------------------------------ + // Zero out the .bss segment (uninitialized common data) + // + movia r2,__bss_start // presume nothing is between + movia r1,_end // the .bss and _end. +1: + stb r0,0(r2) + addi r2,r2,1 + bne r1,r2,1b + // set up the stack pointer, some where higher than _end. The stack space must be greater than 32K for decompress. + movia sp, 0x10000 + add sp,sp,r1 + // save args passed from u-boot + addi sp,sp,-16 + stw r4,0(sp) + stw r5,4(sp) + stw r6,8(sp) + stw r7,12(sp) +/* + * decompress the kernel + */ + call decompress_kernel + +flush_cache: + // flush all cache after loading + // flush the data cache + movia r1,NIOS2_DCACHE_SIZE + movi r2,NIOS2_DCACHE_LINE_SIZE +data_flush: + flushd (r1) + sub r1, r1, r2 + bgt r1, zero, data_flush + // flush the instruction cache + movia r1,NIOS2_ICACHE_SIZE + movi r2,NIOS2_ICACHE_LINE_SIZE +text_flush: + flushi r1 + sub r1, r1, r2 + bgt r1, zero, text_flush + // then flush the pipeline + flushp + // pass saved args to kernel + ldw r4,0(sp) + ldw r5,4(sp) + ldw r6,8(sp) + ldw r7,12(sp) + movia r1,LINUX_SDRAM_START + jmp r1 + + .balign 512 +fake_headers_as_bzImage: + .short 0 + .ascii "HdrS" + .short 0x0202 + .short 0 + .short 0 + .byte 0x00, 0x10 + .short 0 + .byte 0 + .byte 1 + .byte 0x00, 0x80 + .long 0 + .long 0 + diff --git a/arch/nios2nommu/boot/compressed/install.sh b/arch/nios2nommu/boot/compressed/install.sh new file mode 100644 index 00000000..6d72e9e7 --- /dev/null +++ b/arch/nios2nommu/boot/compressed/install.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# arch/sh/boot/install.sh +# +# 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. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy +# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi +# +# "make install" script for sh architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi diff --git a/arch/nios2nommu/boot/compressed/misc.c b/arch/nios2nommu/boot/compressed/misc.c new file mode 100644 index 00000000..c513e6ea --- /dev/null +++ b/arch/nios2nommu/boot/compressed/misc.c @@ -0,0 +1,208 @@ +/* + * arch/nios2nommu/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for SH by Stuart Menefy, Aug 1999 + * + * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000 + */ + +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +#include "nios2_sio.c" + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +int puts(const char *); + +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error"); + if (free_mem_ptr == 0) error("Memory error"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("Out of memory"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\nERROR\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +void decompress_kernel(void) +{ + output_data = (void *)nasys_program_mem; + output_ptr = 0; + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); +} diff --git a/arch/nios2nommu/boot/compressed/nios2_sio.c b/arch/nios2nommu/boot/compressed/nios2_sio.c new file mode 100644 index 00000000..8630c8f4 --- /dev/null +++ b/arch/nios2nommu/boot/compressed/nios2_sio.c @@ -0,0 +1,57 @@ + +static int putchar(int ch); + +static int puts(const char *s) + { + while(*s) + putchar(*s++); + return 0; + } + +#include +#include + +#if defined(CONFIG_SERIAL_AJUART_CONSOLE) + +#define IORD_ALTERA_AVALON_JTAG_UART_DATA(base) inl(base) +#define IOWR_ALTERA_AVALON_JTAG_UART_DATA(base, data) outl(data, base) +#define IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base) inl(base+4) +#define IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(base, data) outl(data, base+4) +#define ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK (0xFFFF0000u) +#define ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_OFST (16) + +static void jtag_putc(int ch) +{ + unsigned base = na_jtag_uart; + while ((IORD_ALTERA_AVALON_JTAG_UART_CONTROL(base) & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK) == 0); + IOWR_ALTERA_AVALON_JTAG_UART_DATA(base, ch); +} + +static int putchar(int ch) +{ + jtag_putc( ch ); + return ch; +} + +#elif defined(CONFIG_NIOS_SERIAL_CONSOLE) + +static void nr_txchar(int ch) +{ + while ((na_uart0->np_uartstatus & np_uartstatus_trdy_mask) == 0); + na_uart0->np_uarttxdata = ch; +} + +static int putchar(int ch) +{ + nr_txchar( ch ); if (ch=='\n') nr_txchar( '\r' ); + return ch; +} + +#else + +static int putchar(int ch) +{ + return ch; +} + +#endif diff --git a/arch/nios2nommu/defconfig b/arch/nios2nommu/defconfig new file mode 100644 index 00000000..40629cb2 --- /dev/null +++ b/arch/nios2nommu/defconfig @@ -0,0 +1,690 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-uc1 +# +# CONFIG_MMU is not set +# CONFIG_FPU is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="../romfs ../vendors/Altera/nios2nommu/romfs_list" +CONFIG_INITRAMFS_ROOT_UID=500 +CONFIG_INITRAMFS_ROOT_GID=500 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SLAB=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" + +# +# Processor type and features +# + +# +# Platform dependant setup +# +CONFIG_NIOS2=y +# CONFIG_MICROTRONIX_UKIT is not set +# CONFIG_MICROTRONIX_STRATIX is not set +# CONFIG_MICROTRONIX_CYCLONE is not set +# CONFIG_MICROTRONIX_PSK is not set +CONFIG_ALTERA_STRATIX=y +# CONFIG_ALTERA_STRATIX_PRO is not set +# CONFIG_ALTERA_STRATIX_II is not set +# CONFIG_ALTERA_CYCLONE is not set +# CONFIG_ALTERA_CYCLONE_1C12_EVAL is not set +# CONFIG_ALTERA_DE2 is not set +# CONFIG_NIOS2_HW_MUL_OFF is not set +CONFIG_NIOS2_HW_MUL=y +# CONFIG_NIOS2_HW_MULX is not set + +# +# Platform drivers Options +# +# CONFIG_AVALON_DMA is not set +# CONFIG_PIO_DEVICES is not set +# CONFIG_PCI is not set +# CONFIG_FB_ALTERA is not set +# CONFIG_SERIO_ALTPS2 is not set +# CONFIG_I2C_GPIO is not set + +# +# Miscellaneous Options +# +CONFIG_EXCALIBUR=y +# CONFIG_BREAK_ON_START is not set +CONFIG_LARGE_ALLOCS=y +CONFIG_RAMKERNEL=y +CONFIG_PREEMPT=y +# CONFIG_PREEMPT_TIMES is not set +CONFIG_CMDLINE="" +# CONFIG_PASS_CMDLINE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_BOOT_LINK_OFFSET=0x00500000 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_KCORE_AOUT=y +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPSEC_NAT_TRAVERSAL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_KLIPS is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_OPEN_ETH is not set +# CONFIG_MTIP1000_ETH is not set +# CONFIG_NE2000 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NIOS_LCD_16207 is not set +# CONFIG_NIOS_BUTTON is not set +# CONFIG_LEDMAN is not set +# CONFIG_SNAPDOG is not set +# CONFIG_FAST_TIMER is not set +# CONFIG_RESETSWITCH is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_NIOS_SERIAL is not set +CONFIG_SERIAL_AJUART=y +CONFIG_SERIAL_AJUART_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=10 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_M41T11M6 is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_DIRECTIO is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_SYSCTL is not set +CONFIG_SYSFS=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Debug +# +# CONFIG_COREDUMP_PRINTK is not set + +# +# Kernel hacking +# +# CONFIG_FULLDEBUG is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_NO_KERNEL_MSG is not set +CONFIG_LOG_BUF_SHIFT=14 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y diff --git a/arch/nios2nommu/drivers/Kconfig b/arch/nios2nommu/drivers/Kconfig new file mode 100644 index 00000000..42e193e6 --- /dev/null +++ b/arch/nios2nommu/drivers/Kconfig @@ -0,0 +1,24 @@ +# Platfrom drivers configuration + +source "arch/nios2nommu/drivers/pci/Kconfig" + +config FB_ALTERA + tristate "Avalon VGA controller support" + select FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the frame buffer device driver for the VGA controller + in SOPC Builder. + +config SERIO_ALTPS2 + tristate "PS2 controller" + select SERIO + +config I2C_GPIO + tristate "GPIO-Based I2C Interface" + select I2C + select I2C_ALGOBIT + help + Say Y here if you use GPIO lines for an I2C bus. diff --git a/arch/nios2nommu/drivers/Makefile b/arch/nios2nommu/drivers/Makefile new file mode 100644 index 00000000..757c8552 --- /dev/null +++ b/arch/nios2nommu/drivers/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Linux nios2-specific device drivers. +# + +obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_FB_ALTERA) += altfb.o +obj-$(CONFIG_SERIO_ALTPS2) += altps2.o +obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o diff --git a/arch/nios2nommu/drivers/altfb.c b/arch/nios2nommu/drivers/altfb.c new file mode 100644 index 00000000..cebd6598 --- /dev/null +++ b/arch/nios2nommu/drivers/altfb.c @@ -0,0 +1,234 @@ +/* + * Altera VGA controller + * + * linux/drivers/video/vfb.c -- Virtual frame buffer device + * + * Copyright (C) 2002 James Simmons + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define vgabase na_vga_controller_0 +#define XRES 640 +#define YRES 480 +#define BPX 16 + + /* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + * + * The default can be overridden if the driver is compiled as a module + */ + +#define VIDEOMEMSIZE (XRES * YRES * (BPX>>3)) + +static void *videomemory; +static u_long videomemorysize = VIDEOMEMSIZE; +module_param(videomemorysize, ulong, 0); + +static struct fb_var_screeninfo altfb_default __initdata = { + .xres = XRES, + .yres = YRES, + .xres_virtual = XRES, + .yres_virtual = YRES, + .bits_per_pixel = BPX, +#if (BPX == 16) + .red = { 11, 5, 0 }, + .green = { 5, 6, 0 }, + .blue = { 0, 5, 0 }, +#else // BPX == 24 + .red = { 16, 8, 0 }, + .green = { 8, 8, 0 }, + .blue = { 0, 8, 0 }, +#endif + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + // timing useless ? + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo altfb_fix __initdata = { + .id = "Altera FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = (XRES * (BPX>>3)), + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static int altfb_mmap(struct fb_info *info, + struct vm_area_struct *vma); + +static struct fb_ops altfb_ops = { + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = altfb_mmap, +}; + + + /* + * Most drivers don't need their own mmap function + */ + +static int altfb_mmap(struct fb_info *info, + struct vm_area_struct *vma) +{ + /* this is uClinux (no MMU) specific code */ + vma->vm_flags |= (VM_RESERVED | VM_MAYSHARE); + vma->vm_start = (unsigned) videomemory; + return 0; +} + + /* + * Initialisation + */ + +static void altfb_platform_release(struct device *device) +{ + // This is called when the reference count goes to zero. + dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); +} + +static int __init altfb_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + dma_addr_t handle; + + /* + * For real video cards we use ioremap. + */ + if (!(videomemory = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(videomemorysize), &handle, GFP_KERNEL))) { + printk(KERN_ERR "altfb: unable to allocate screen memory\n"); + return retval; + } + altfb_fix.smem_start = handle; + altfb_fix.smem_len = videomemorysize; + + info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); + if (!info) + goto err; + + info->screen_base = (char __iomem *)videomemory; + info->fbops = &altfb_ops; + info->var = altfb_default; + info->fix = altfb_fix; + info->pseudo_palette = info->par; + info->par = NULL; + info->flags = FBINFO_FLAG_DEFAULT; + + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) + goto err1; + + retval = register_framebuffer(info); + if (retval < 0) + goto err2; + platform_set_drvdata(dev, info); + + outl(0x0,vgabase+0); // Reset the VGA controller + outl(videomemory,vgabase+4); // Where our frame buffer starts + outl(videomemorysize,vgabase+8); // amount of memory needed + outl(0x1,vgabase+0); // Set the go bit + + printk(KERN_INFO + "fb%d: Altera frame buffer device, using %ldK of video memory\n", + info->node, videomemorysize >> 10); + // printk("vga %08x, video %08x+%08x\n",vgabase,videomemory,videomemorysize); + return 0; +err2: + fb_dealloc_cmap(&info->cmap); +err1: + framebuffer_release(info); +err: + dma_free_noncoherent(&dev->dev, videomemorysize, videomemory, handle); + return retval; +} + +static int altfb_remove(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + + if (info) { + unregister_framebuffer(info); + dma_free_noncoherent(&dev->dev, videomemorysize, videomemory, altfb_fix.smem_start); + framebuffer_release(info); + } + return 0; +} + +static struct platform_driver altfb_driver = { + .probe = altfb_probe, + .remove = altfb_remove, + .driver = { + .name = "altfb", + }, +}; + +static struct platform_device altfb_device = { + .name = "altfb", + .id = 0, + .dev = { + .release = altfb_platform_release, + } +}; + +static int __init altfb_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&altfb_driver); + + if (!ret) { + ret = platform_device_register(&altfb_device); + if (ret) + platform_driver_unregister(&altfb_driver); + } + return ret; +} + +module_init(altfb_init); + +#ifdef MODULE +static void __exit altfb_exit(void) +{ + platform_device_unregister(&altfb_device); + platform_driver_unregister(&altfb_driver); +} + +module_exit(altfb_exit); + +MODULE_LICENSE("GPL"); +#endif /* MODULE */ diff --git a/arch/nios2nommu/drivers/altps2.c b/arch/nios2nommu/drivers/altps2.c new file mode 100644 index 00000000..4a6523c3 --- /dev/null +++ b/arch/nios2nommu/drivers/altps2.c @@ -0,0 +1,193 @@ +/* + * altera DE2 PS/2 + * + * linux/drivers/input/serio/sa1111ps2.c + * + * Copyright (C) 2002 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +struct ps2if { + struct serio *io; + struct platform_device *dev; + unsigned base; + unsigned irq; +}; + +/* + * Read all bytes waiting in the PS2 port. There should be + * at the most one, but we loop for safety. If there was a + * framing error, we have to manually clear the status. + */ +static irqreturn_t ps2_rxint(int irq, void *dev_id) +{ + struct ps2if *ps2if = dev_id; + unsigned int status; + int handled = IRQ_NONE; + + while ((status = inl(ps2if->base)) & 0xffff0000) { + serio_interrupt(ps2if->io, status & 0xff, 0); + handled = IRQ_HANDLED; + } + return handled; +} + +/* + * Write a byte to the PS2 port. We have to wait for the + * port to indicate that the transmitter is empty. + */ +static int ps2_write(struct serio *io, unsigned char val) +{ + struct ps2if *ps2if = io->port_data; + outl(val,ps2if->base); + // should check command send error + if (inl(ps2if->base+4) & (1<<10)) + { + // printk("ps2 write error %02x\n",val); + } + return 0; +} + +static int ps2_open(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + int ret; + + ret = request_irq(ps2if->irq, ps2_rxint, 0, + "altps2", ps2if); + if (ret) { + printk(KERN_ERR "altps2: could not allocate IRQ%d: %d\n", + ps2if->irq, ret); + return ret; + } + outl(1,ps2if->base+4); // enable rx irq + return 0; +} + +static void ps2_close(struct serio *io) +{ + struct ps2if *ps2if = io->port_data; + outl(0,ps2if->base); // disable rx irq + free_irq(ps2if->irq, ps2if); +} + +/* + * Add one device to this driver. + */ +static int ps2_probe(struct platform_device *dev) +{ + struct ps2if *ps2if; + struct serio *serio; + unsigned int status; + int ret; + + ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + ret = -ENOMEM; + goto free; + } + + memset(ps2if, 0, sizeof(struct ps2if)); + memset(serio, 0, sizeof(struct serio)); + + serio->id.type = SERIO_8042; + serio->write = ps2_write; + serio->open = ps2_open; + serio->close = ps2_close; + strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; + ps2if->dev = dev; + platform_set_drvdata(dev, ps2if); + + /* + * Request the physical region for this PS2 port. + */ + if (dev->num_resources < 2) { + ret = -ENODEV; + goto out; + } + if (!request_mem_region(dev->resource[0].start, + 4, + "altps2")) { + ret = -EBUSY; + goto free; + } + ps2if->base = dev->resource[0].start; + ps2if->irq = dev->resource[1].start; + printk("altps2 : base %08x irq %d\n",ps2if->base,ps2if->irq); + // clear fifo + while ((status = inl(ps2if->base)) & 0xffff0000) { + } + + serio_register_port(ps2if->io); + return 0; + + out: + release_mem_region(dev->resource[0].start,4); + free: + platform_set_drvdata(dev, NULL); + kfree(ps2if); + kfree(serio); + return ret; +} + +/* + * Remove one device from this driver. + */ +static int ps2_remove(struct platform_device *dev) +{ + struct ps2if *ps2if = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + serio_unregister_port(ps2if->io); + release_mem_region(dev->resource[0].start,4); + + kfree(ps2if); + + return 0; +} + +/* + * Our device driver structure + */ +static struct platform_driver ps2_driver = { + .probe = ps2_probe, + .remove = ps2_remove, + .driver = { + .name = "altps2", + }, +}; + +static int __init ps2_init(void) +{ + return platform_driver_register(&ps2_driver); +} + +static void __exit ps2_exit(void) +{ + platform_driver_unregister(&ps2_driver); +} + +module_init(ps2_init); +module_exit(ps2_exit); diff --git a/arch/nios2nommu/drivers/i2c-gpio.c b/arch/nios2nommu/drivers/i2c-gpio.c new file mode 100644 index 00000000..4b88753b --- /dev/null +++ b/arch/nios2nommu/drivers/i2c-gpio.c @@ -0,0 +1,166 @@ +/* + * drivers/i2c/busses/i2c-gpio.c for Nios2 + * + * drivers/i2c/busses/i2c-ixp2000.c + * + * I2C adapter for IXP2000 systems using GPIOs for I2C bus + * + * Author: Deepak Saxena + * Based on IXDP2400 code by: Naeem M. Afzal + * Made generic by: Jeff Daly + * + * Copyright (c) 2003-2004 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. + * + * From Jeff Daly: + * + * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any + * IXP2000 platform if it uses the HW GPIO in the same manner. Basically, + * SDA and SCL GPIOs have external pullups. Setting the respective GPIO to + * an input will make the signal a '1' via the pullup. Setting them to + * outputs will pull them down. + * + * The GPIOs are open drain signals and are used as configuration strap inputs + * during power-up so there's generally a buffer on the board that needs to be + * 'enabled' to drive the GPIOs. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static inline int gpio_scl_pin(void *data) +{ + return ((struct gpio_i2c_pins*)data)->scl_pin; +} + +static inline int gpio_sda_pin(void *data) +{ + return ((struct gpio_i2c_pins*)data)->sda_pin; +} + + +static void gpio_bit_setscl(void *data, int val) +{ + int i = 5000; + + if (val) { + outl(3,gpio_scl_pin(data)); + while(!(inl(gpio_scl_pin(data)) & 1) && i--); + } else { + outl(2,gpio_scl_pin(data)); + } +} + +static void gpio_bit_setsda(void *data, int val) +{ + if (val) { + outl(1,gpio_sda_pin(data)); + } else { + outl(0,gpio_sda_pin(data)); + } +} + +static int gpio_bit_getscl(void *data) +{ + return inl(gpio_scl_pin(data)) & 1; +} + +static int gpio_bit_getsda(void *data) +{ + return inl(gpio_sda_pin(data)) & 1; +} + +struct gpio_i2c_data { + struct gpio_i2c_pins *gpio_pins; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo_data; +}; + +static int gpio_i2c_remove(struct platform_device *plat_dev) +{ + struct gpio_i2c_data *drv_data = platform_get_drvdata(plat_dev); + + platform_set_drvdata(plat_dev, NULL); + + i2c_bit_del_bus(&drv_data->adapter); + + kfree(drv_data); + + return 0; +} + +static int gpio_i2c_probe(struct platform_device *plat_dev) +{ + int err; + struct gpio_i2c_pins *gpio = plat_dev->dev.platform_data; + struct gpio_i2c_data *drv_data = + kzalloc(sizeof(struct gpio_i2c_data), GFP_KERNEL); + + if (!drv_data) + return -ENOMEM; + drv_data->gpio_pins = gpio; + + drv_data->algo_data.data = gpio; + drv_data->algo_data.setsda = gpio_bit_setsda; + drv_data->algo_data.setscl = gpio_bit_setscl; + drv_data->algo_data.getsda = gpio_bit_getsda; + drv_data->algo_data.getscl = gpio_bit_getscl; + drv_data->algo_data.udelay = 6; + drv_data->algo_data.timeout = 100; + + drv_data->adapter.id = I2C_HW_B_IXP2000, // borrowed, + strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, + I2C_NAME_SIZE); + drv_data->adapter.algo_data = &drv_data->algo_data, + + drv_data->adapter.dev.parent = &plat_dev->dev; + drv_data->adapter.class = I2C_CLASS_ALL; + + outl(1,gpio->sda_pin); + outl(1,gpio->scl_pin); + + if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) { + dev_err(&plat_dev->dev, "Could not install, error %d\n", err); + kfree(drv_data); + return err; + } + + platform_set_drvdata(plat_dev, drv_data); + printk("i2c-gpio driver at %08x\n",gpio->sda_pin); + + return 0; +} + +static struct platform_driver gpio_i2c_driver = { + .probe = gpio_i2c_probe, + .remove = gpio_i2c_remove, + .driver = { + .name = "GPIO-I2C", + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_i2c_init(void) +{ + return platform_driver_register(&gpio_i2c_driver); +} + +static void __exit gpio_i2c_exit(void) +{ + platform_driver_unregister(&gpio_i2c_driver); +} + +module_init(gpio_i2c_init); +module_exit(gpio_i2c_exit); + diff --git a/arch/nios2nommu/drivers/pci/Kconfig b/arch/nios2nommu/drivers/pci/Kconfig new file mode 100644 index 00000000..bc3c29b1 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/Kconfig @@ -0,0 +1,6 @@ +config PCI_ALTPCI + bool "Altera PCI host bridge" + select PCI + select PCI_AUTO + select PCI_AUTO_UPDATE_RESOURCES + default n diff --git a/arch/nios2nommu/drivers/pci/Makefile b/arch/nios2nommu/drivers/pci/Makefile new file mode 100644 index 00000000..5d158fe4 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the PCI specific kernel interface routines under Linux. +# + +obj-y += pci.o +obj-$(CONFIG_PCI_ALTPCI) += altpci.o +obj-$(CONFIG_PCI_ALTPCI) += setup-irq.o +obj-$(CONFIG_PCI_AUTO) += pci-auto.o diff --git a/arch/nios2nommu/drivers/pci/altpci.c b/arch/nios2nommu/drivers/pci/altpci.c new file mode 100644 index 00000000..85959ea7 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/altpci.c @@ -0,0 +1,204 @@ +/* arch/sh/kernel/pci.c + * $Id: altpci.c,v 1.1 2006/07/05 06:23:17 gerg Exp $ + * + * Copyright (c) 2002 M. R. Brown + * + * + * These functions are collected here to reduce duplication of common + * code amongst the many platform-specific PCI support code files. + * + * These routines require the following board-specific routines: + * void pcibios_fixup_irqs(); + * + * See include/asm-sh/pci.h for more information. + */ + +#include +#include +#include + +/* + * Direct access to PCI hardware... + */ +#define pcicfg_space (na_pci_compiler_0_PCI_Bus_Access) // avalon space +#define pciio (pcicfg_space+0x100000) // pci io device base in avalon space +#define pcimm (pcicfg_space+0x200000) // pci mem device base in avalon space + // idsel of ad11=dev0,ad12=dev1 , using type 0 config request +#define pcicfg(dev,fun,reg) (pcicfg_space | ((dev)<<11) | ((fun)<<8) | (reg)) // cfg space + +// FIX ME for your board, dram device for external pci masters access +static int __init alt_pci_init(void) +{ + unsigned dev,fun; + // setup dram bar + dev=0; fun=0; + outl(nasys_program_mem,pcicfg(dev,fun,0x10)); // mem space + outw(0x0006,pcicfg(dev,fun,0x04)); // enable master, mem space + return 0; +} + +subsys_initcall(alt_pci_init); + +#define PCICFG(bus, devfn, where) (pcicfg_space | (bus->number << 16) | (devfn << 8) | (where & ~3)) +#define ALT_PCI_IO_BASE (pciio) +#define ALT_PCI_IO_SIZE 0x100000 +#define ALT_PCI_MEMORY_BASE (pcimm) +#define ALT_PCI_MEM_SIZE 0x100000 + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +// FIX ME for your board, number of pci bus, and number of devices +static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn) +{ + if (bus->number > 0 || PCI_SLOT(devfn) == 0 || PCI_SLOT(devfn) > 2) + return -1; + + return 0; +} + +static int alt_pci_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + + if (pci_range_ck(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + // local_irq_save(flags); + data = inl(PCICFG(bus, devfn, where)); + // local_irq_restore(flags); + + switch (size) { + case 1: + *val = (data >> ((where & 3) << 3)) & 0xff; + break; + case 2: + *val = (data >> ((where & 2) << 3)) & 0xffff; + break; + case 4: + *val = data; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + + return PCIBIOS_SUCCESSFUL; +} + +/* + * we'll do a read, + * mask,write operation. + * We'll allow an odd byte offset, though it should be illegal. + */ +static int alt_pci_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + int shift; + u32 data; + + if (pci_range_ck(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + // local_irq_save(flags); + data = inl(PCICFG(bus, devfn, where)); + // local_irq_restore(flags); + + switch (size) { + case 1: + shift = (where & 3) << 3; + data &= ~(0xff << shift); + data |= ((val & 0xff) << shift); + break; + case 2: + shift = (where & 2) << 3; + data &= ~(0xffff << shift); + data |= ((val & 0xffff) << shift); + break; + case 4: + data = val; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + + outl(data, PCICFG(bus, devfn, where)); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops alt_pci_ops = { + .read = alt_pci_read, + .write = alt_pci_write, +}; + +static struct resource alt_io_resource = { + .name = "ALTPCI IO", + .start = ALT_PCI_IO_BASE, + .end = ALT_PCI_IO_BASE + ALT_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource alt_mem_resource = { + .name = "ALTPCI mem", + .start = ALT_PCI_MEMORY_BASE, + .end = ALT_PCI_MEMORY_BASE + ALT_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +extern struct pci_ops alt_pci_ops; + +struct pci_channel board_pci_channels[] = { + { &alt_pci_ops, &alt_io_resource, &alt_mem_resource, 0, 0xff }, + { NULL, NULL, NULL, 0, 0 }, +}; + +char *pcibios_setup(char *option) +{ + /* Nothing for us to handle. */ + return(option); +} + +void pcibios_fixup_bus(struct pci_bus *b) +{ +} + +/* + * IRQ functions + */ +static u8 __init altpci_no_swizzle(struct pci_dev *dev, u8 *pin) +{ + /* no swizzling */ + return PCI_SLOT(dev->devfn); +} + +// FIX ME for your board, nios2 irqn mapping +int __init pcibios_map_platform_irq(u8 slot, u8 pin) +{ + int irq = na_irqn_0_irq + ((slot-1)*4) + (pin-1); + // printk("map slot %d pin %d irq %d\n",slot,pin,irq); + return irq; +} + +static int altpci_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq = -1; + + /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ + irq = pcibios_map_platform_irq(slot,pin); + if( irq < 0 ) { + // printk("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); + return irq; + } + + // printk("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); + + return irq; +} + +void __init pcibios_fixup_irqs(void) +{ + pci_fixup_irqs(altpci_no_swizzle, altpci_pci_lookup_irq); +} + diff --git a/arch/nios2nommu/drivers/pci/pci-auto.c b/arch/nios2nommu/drivers/pci/pci-auto.c new file mode 100644 index 00000000..2f31b183 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/pci-auto.c @@ -0,0 +1,559 @@ +/* + * PCI autoconfiguration library + * + * Author: Matt Porter + * + * Copyright 2000, 2001 MontaVista Software Inc. + * Copyright 2001 Bradley D. LaRonde + * Copyright 2003 Paul Mundt + * + * 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. + */ + +/* + * Modified for MIPS by Jun Sun, jsun@mvista.com + * + * . Simplify the interface between pci_auto and the rest: a single function. + * . Assign resources from low address to upper address. + * . change most int to u32. + * + * Further modified to include it as mips generic code, ppopov@mvista.com. + * + * 2001-10-26 Bradley D. LaRonde + * - Add a top_bus argument to the "early config" functions so that + * they can set a fake parent bus pointer to convince the underlying + * pci ops to use type 1 configuration for sub busses. + * - Set bridge base and limit registers correctly. + * - Align io and memory base properly before and after bridge setup. + * - Don't fall through to pci_setup_bars for bridge. + * - Reformat the debug output to look more like lspci's output. + * + * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org + * + * 2003-08-05 Paul Mundt + * - Don't update the BAR values on systems that already have valid addresses + * and don't want these updated for whatever reason, by way of a new config + * option check. However, we still read in the old BAR values so that they + * can still be reported through the debug output. + */ + +#include +#include +#include +#include + +#undef DEBUG +#define DEBUG // you can remove debug message here + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* + * These functions are used early on before PCI scanning is done + * and all of the pci_dev and pci_bus structures have been created. + */ +static struct pci_dev *fake_pci_dev(struct pci_channel *hose, + int top_bus, int busnr, int devfn) +{ + static struct pci_dev dev; + static struct pci_bus bus; + + dev.bus = &bus; + dev.sysdata = hose; + dev.devfn = devfn; + bus.number = busnr; + bus.ops = hose->pci_ops; + + if(busnr != top_bus) + /* Fake a parent bus structure. */ + bus.parent = &bus; + else + bus.parent = NULL; + + return &dev; +} + +#define EARLY_PCI_OP(rw, size, type) \ +int early_##rw##_config_##size(struct pci_channel *hose, \ + int top_bus, int bus, int devfn, int offset, type value) \ +{ \ + return pci_##rw##_config_##size( \ + fake_pci_dev(hose, top_bus, bus, devfn), \ + offset, value); \ +} + +EARLY_PCI_OP(read, byte, u8 *) +EARLY_PCI_OP(read, word, u16 *) +EARLY_PCI_OP(read, dword, u32 *) +EARLY_PCI_OP(write, byte, u8) +EARLY_PCI_OP(write, word, u16) +EARLY_PCI_OP(write, dword, u32) + +static struct resource *io_resource_inuse; +static struct resource *mem_resource_inuse; + +static u32 pciauto_lower_iospc; +static u32 pciauto_upper_iospc; + +static u32 pciauto_lower_memspc; +static u32 pciauto_upper_memspc; + +static void __init +pciauto_setup_bars(struct pci_channel *hose, + int top_bus, + int current_bus, + int pci_devfn, + int bar_limit) +{ + u32 bar_response, bar_size, bar_value; + u32 bar, addr_mask, bar_nr = 0; + u32 * upper_limit; + u32 * lower_limit; + int found_mem64 = 0; + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { +#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) + u32 bar_addr; + + /* Read the old BAR value */ + early_read_config_dword(hose, top_bus, + current_bus, + pci_devfn, + bar, + &bar_addr); +#endif + + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, top_bus, + current_bus, + pci_devfn, + bar, + 0xffffffff); + + early_read_config_dword(hose, top_bus, + current_bus, + pci_devfn, + bar, + &bar_response); + +#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) + /* + * Write the old BAR value back out, only update the BAR + * if we implicitly want resources to be updated, which + * is done by the generic code further down. -- PFM. + */ + early_write_config_dword(hose, top_bus, + current_bus, + pci_devfn, + bar, + bar_addr); +#endif + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* + * Workaround for a BAR that doesn't use its upper word, + * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457). + * bdl + */ + if (!(bar_response & 0xffff0000)) + bar_response |= 0xffff0000; + +retry: + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + lower_limit = &pciauto_lower_iospc; + DBG(" I/O"); + } else { + if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + lower_limit = &pciauto_lower_memspc; + DBG(" Mem"); + } + + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; + + if ((bar_value + bar_size) > *upper_limit) { + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + if (io_resource_inuse->child) { + io_resource_inuse = + io_resource_inuse->child; + pciauto_lower_iospc = + io_resource_inuse->start; + pciauto_upper_iospc = + io_resource_inuse->end + 1; + goto retry; + } + + } else { + if (mem_resource_inuse->child) { + mem_resource_inuse = + mem_resource_inuse->child; + pciauto_lower_memspc = + mem_resource_inuse->start; + pciauto_upper_memspc = + mem_resource_inuse->end + 1; + goto retry; + } + } + DBG(" unavailable -- skipping, value %x size %x\n", + bar_value, bar_size); + continue; + } + +#ifdef CONFIG_PCI_AUTO_UPDATE_RESOURCES + /* Write it out and update our limit */ + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + bar, bar_value); +#endif + + *lower_limit = bar_value + bar_size; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) { + bar += 4; + early_write_config_dword(hose, top_bus, + current_bus, + pci_devfn, + bar, + 0x00000000); + } + + DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size); + + bar_nr++; + } + +} + +static void __init +pciauto_prescan_setup_bridge(struct pci_channel *hose, + int top_bus, + int current_bus, + int pci_devfn, + int sub_bus) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_PRIMARY_BUS, current_bus); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SECONDARY_BUS, sub_bus + 1); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SUBORDINATE_BUS, 0xff); + + /* Align memory and I/O to 1MB and 4KB boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) + & ~(0x100000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) + & ~(0x1000 - 1); + + /* Set base (lower limit) of address range behind bridge. */ + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_MEMORY_BASE, pciauto_lower_memspc >> 16); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16); + + /* We don't support prefetchable memory for now, so disable */ + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_PREF_MEMORY_BASE, 0); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_PREF_MEMORY_LIMIT, 0); +} + +static void __init +pciauto_postscan_setup_bridge(struct pci_channel *hose, + int top_bus, + int current_bus, + int pci_devfn, + int sub_bus) +{ + u32 temp; + + /* + * [jsun] we always bump up baselines a little, so that if there + * nothing behind P2P bridge, we don't wind up overlapping IO/MEM + * spaces. + */ + pciauto_lower_memspc += 1; + pciauto_lower_iospc += 1; + + /* Configure bus number registers */ + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SUBORDINATE_BUS, sub_bus); + + /* Set upper limit of address range behind bridge. */ + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, top_bus, current_bus, pci_devfn, + PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16); + + /* Align memory and I/O to 1MB and 4KB boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) + & ~(0x100000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) + & ~(0x1000 - 1); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, &temp); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY + | PCI_COMMAND_MASTER); +} + +static void __init +pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose, + int top_bus, + int current_bus, + int pci_devfn, + int sub_bus) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_PRIMARY_BUS, current_bus); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SECONDARY_BUS, sub_bus + 1); + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SUBORDINATE_BUS, 0xff); + + /* Align memory and I/O to 4KB and 4 byte boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) + & ~(0x1000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) + & ~(0x4 - 1); + + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_CB_IO_BASE_0, pciauto_lower_iospc); +} + +static void __init +pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, + int top_bus, + int current_bus, + int pci_devfn, + int sub_bus) +{ + u32 temp; + +#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) + /* + * [jsun] we always bump up baselines a little, so that if there + * nothing behind P2P bridge, we don't wind up overlapping IO/MEM + * spaces. + */ + pciauto_lower_memspc += 1; + pciauto_lower_iospc += 1; +#endif + + /* + * Configure subordinate bus number. The PCI subsystem + * bus scan will renumber buses (reserving three additional + * for this PCI<->CardBus bridge for the case where a CardBus + * adapter contains a P2P or CB2CB bridge. + */ + + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_SUBORDINATE_BUS, sub_bus); + + /* + * Reserve an additional 4MB for mem space and 16KB for + * I/O space. This should cover any additional space + * requirement of unusual CardBus devices with + * additional bridges that can consume more address space. + * + * Although pcmcia-cs currently will reprogram bridge + * windows, the goal is to add an option to leave them + * alone and use the bridge window ranges as the regions + * that are searched for free resources upon hot-insertion + * of a device. This will allow a PCI<->CardBus bridge + * configured by this routine to happily live behind a + * P2P bridge in a system. + */ +#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) + pciauto_lower_memspc += 0x00400000; + pciauto_lower_iospc += 0x00004000; +#endif + + /* Align memory and I/O to 4KB and 4 byte boundaries. */ + pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) + & ~(0x1000 - 1); + pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) + & ~(0x4 - 1); + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, &temp); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +static int __init +pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) +{ + int sub_bus; + u32 pci_devfn, pci_class, cmdstat, found_multi=0; + unsigned short vid, did; + unsigned char header_type; + int devfn_start = 0; + int devfn_stop = 0xff; + + sub_bus = current_bus; + + if (hose->first_devfn) + devfn_start = hose->first_devfn; + if (hose->last_devfn) + devfn_stop = hose->last_devfn; + + for (pci_devfn=devfn_start; pci_devfn> 16, vid, did); + if (pci_class & 0xff) + DBG(" (rev %.2x)", pci_class & 0xff); + DBG("\n"); + + if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { + DBG(" Bridge: primary=%.2x, secondary=%.2x\n", + current_bus, sub_bus + 1); +#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) + pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1); +#endif + pciauto_prescan_setup_bridge(hose, top_bus, current_bus, + pci_devfn, sub_bus); + DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", + sub_bus + 1, + pciauto_lower_iospc, pciauto_lower_memspc); + sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); + DBG("Back to bus %.2x\n", current_bus); + pciauto_postscan_setup_bridge(hose, top_bus, current_bus, + pci_devfn, sub_bus); + continue; + } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) { + DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n", + current_bus, sub_bus + 1); + DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn)); + /* Place CardBus Socket/ExCA registers */ + pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0); + + pciauto_prescan_setup_cardbus_bridge(hose, top_bus, + current_bus, pci_devfn, sub_bus); + + DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", + sub_bus + 1, + pciauto_lower_iospc, pciauto_lower_memspc); + sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); + DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus); + pciauto_postscan_setup_cardbus_bridge(hose, top_bus, + current_bus, pci_devfn, sub_bus); + continue; + } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { + + unsigned char prg_iface; + + early_read_config_byte(hose, top_bus, current_bus, + pci_devfn, PCI_CLASS_PROG, &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { + DBG("Skipping legacy mode IDE controller\n"); + continue; + } + } + + /* + * Found a peripheral, enable some standard + * settings + */ + early_read_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, &cmdstat); + early_write_config_dword(hose, top_bus, current_bus, pci_devfn, + PCI_COMMAND, cmdstat | PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) + early_write_config_byte(hose, top_bus, current_bus, pci_devfn, + PCI_LATENCY_TIMER, 0x80); +#endif + + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5); + } + return sub_bus; +} + +int __init +pciauto_assign_resources(int busno, struct pci_channel *hose) +{ + /* setup resource limits */ + io_resource_inuse = hose->io_resource; + mem_resource_inuse = hose->mem_resource; + + pciauto_lower_iospc = io_resource_inuse->start; + pciauto_upper_iospc = io_resource_inuse->end + 1; + pciauto_lower_memspc = mem_resource_inuse->start; + pciauto_upper_memspc = mem_resource_inuse->end + 1; + DBG("Autoconfig PCI channel 0x%p\n", hose); + DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n", + busno, pciauto_lower_iospc, pciauto_upper_iospc, + pciauto_lower_memspc, pciauto_upper_memspc); + + return pciauto_bus_scan(hose, busno, busno); +} diff --git a/arch/nios2nommu/drivers/pci/pci.c b/arch/nios2nommu/drivers/pci/pci.c new file mode 100644 index 00000000..9f905de2 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/pci.c @@ -0,0 +1,151 @@ +/* arch/sh/kernel/pci.c + * $Id: pci.c,v 1.2 2007/01/25 01:26:48 gerg Exp $ + * + * Copyright (c) 2002 M. R. Brown + * + * + * These functions are collected here to reduce duplication of common + * code amongst the many platform-specific PCI support code files. + * + * These routines require the following board-specific routines: + * void pcibios_fixup_irqs(); + * + * See include/asm-sh/pci.h for more information. + */ + +#include +#include +#include + +static int __init pcibios_init(void) +{ + struct pci_channel *p; + struct pci_bus *bus; + int busno; + +#ifdef CONFIG_PCI_AUTO + /* assign resources */ + busno = 0; + for (p = board_pci_channels; p->pci_ops != NULL; p++) { + busno = pciauto_assign_resources(busno, p) + 1; + } +#endif + + /* scan the buses */ + busno = 0; + for (p= board_pci_channels; p->pci_ops != NULL; p++) { + bus = pci_scan_bus(busno, p->pci_ops, p); + busno = bus->subordinate+1; + } + + /* board-specific fixups */ + pcibios_fixup_irqs(); + + return 0; +} + +subsys_initcall(pcibios_init); + +void +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= IORESOURCE_ROM_ENABLE; + new |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", pci_name(dev), resource, + new, check); + } +} + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + */ +void pcibios_align_resource(void *data, struct resource *res, + resource_size_t size, resource_size_t align) +{ + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +} + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + if (!(mask & (1 << idx))) + continue; + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +/* + * If we set up a device for bus mastering, we need to check and set + * the latency timer as it may not be properly set. + */ +unsigned int pcibios_max_latency = 255; + +void pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} diff --git a/arch/nios2nommu/drivers/pci/setup-irq.c b/arch/nios2nommu/drivers/pci/setup-irq.c new file mode 100644 index 00000000..0fa8f987 --- /dev/null +++ b/arch/nios2nommu/drivers/pci/setup-irq.c @@ -0,0 +1 @@ +#include "../../../../drivers/pci/setup-irq.c" diff --git a/arch/nios2nommu/kernel/ChangeLog b/arch/nios2nommu/kernel/ChangeLog new file mode 100644 index 00000000..7f1449d2 --- /dev/null +++ b/arch/nios2nommu/kernel/ChangeLog @@ -0,0 +1,27 @@ +2004-06-17 Ken Hill + + * process.c (machine_restart): Add code to disable interrups and + jump to the cpu reset address. + (machine_halt): Add code to disable interrupts and spinlock. + (machine_power_off): Add code to disable interrupts and spinlock. + +2004-06-16 Ken Hill + + * nios2_ksyms.c: Remove hard_reset_now. + +2004-06-10 Ken Hill + + * nios2_ksyms.c: Add EXPORT_SYMBOL_NOVERS(__down) to solve insmod for + some modules. + +2004-06-02 Ken Hill + + * entry.S (software_exception): Add a safety catch for old applications that may + have been linked against an older library. This does not add any overhead to + system call processing. + +2004-04-15 Ken Hill + + * setup.c (setup_arch): Remove ROMFS message from debug printk kernel message. + Add copyright and GNU license notice. + diff --git a/arch/nios2nommu/kernel/Makefile b/arch/nios2nommu/kernel/Makefile new file mode 100644 index 00000000..a056ff1e --- /dev/null +++ b/arch/nios2nommu/kernel/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +extra-y := head.o init_task.o vmlinux.lds + +obj-y := entry.o traps.o irq.o syscalltable.o \ + process.o signal.o setup.o sys_nios2.o \ + semaphore.o io.o usb.o\ + time.o ptrace.o start.o nios2_ksyms.o + +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_CONSOLE) += console.o +obj-$(CONFIG_PIO_DEVICES) += pio.o +obj-$(CONFIG_AVALON_DMA) += dma.o + + diff --git a/arch/nios2nommu/kernel/asm-offsets.c b/arch/nios2nommu/kernel/asm-offsets.c new file mode 100644 index 00000000..dd93a81c --- /dev/null +++ b/arch/nios2nommu/kernel/asm-offsets.c @@ -0,0 +1,201 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* offsets into the irq_cpustat_t struct */ + DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); + + /* offsets into the irq_node struct */ + DEFINE(IRQ_HANDLER, offsetof(struct irq_hand, handler)); + DEFINE(IRQ_FLAGS, offsetof(struct irq_hand, flags)); + DEFINE(IRQ_DEV_ID, offsetof(struct irq_hand, dev_id)); + DEFINE(IRQ_DEVNAME, offsetof(struct irq_hand, devname)); + + /* offsets into the thread struct */ + DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(THREAD_KPSR, offsetof(struct thread_struct, kpsr)); + DEFINE(THREAD_KESR, offsetof(struct thread_struct, kesr)); + DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags)); + + /* offsets into the pt_regs */ + DEFINE(PT_ORIG_R2, offsetof(struct pt_regs, orig_r2)); + DEFINE(PT_R1, offsetof(struct pt_regs, r1)); + DEFINE(PT_R2, offsetof(struct pt_regs, r2)); + DEFINE(PT_R3, offsetof(struct pt_regs, r3)); + DEFINE(PT_R4, offsetof(struct pt_regs, r4)); + DEFINE(PT_R5, offsetof(struct pt_regs, r5)); + DEFINE(PT_R6, offsetof(struct pt_regs, r6)); + DEFINE(PT_R7, offsetof(struct pt_regs, r7)); + DEFINE(PT_R8, offsetof(struct pt_regs, r8)); + DEFINE(PT_R9, offsetof(struct pt_regs, r9)); + DEFINE(PT_R10, offsetof(struct pt_regs, r10)); + DEFINE(PT_R11, offsetof(struct pt_regs, r11)); + DEFINE(PT_R12, offsetof(struct pt_regs, r12)); + DEFINE(PT_R13, offsetof(struct pt_regs, r13)); + DEFINE(PT_R14, offsetof(struct pt_regs, r14)); + DEFINE(PT_R15, offsetof(struct pt_regs, r15)); + DEFINE(PT_EA, offsetof(struct pt_regs, ea)); + DEFINE(PT_RA, offsetof(struct pt_regs, ra)); + DEFINE(PT_FP, offsetof(struct pt_regs, fp)); + DEFINE(PT_SP, offsetof(struct pt_regs, sp)); + DEFINE(PT_GP, offsetof(struct pt_regs, gp)); + DEFINE(PT_ESTATUS, offsetof(struct pt_regs, estatus)); + DEFINE(PT_STATUS_EXTENSION, offsetof(struct pt_regs, status_extension)); + DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); + + /* offsets into the switch_stack */ + DEFINE(SW_R16, offsetof(struct switch_stack, r16)); + DEFINE(SW_R17, offsetof(struct switch_stack, r17)); + DEFINE(SW_R18, offsetof(struct switch_stack, r18)); + DEFINE(SW_R19, offsetof(struct switch_stack, r19)); + DEFINE(SW_R20, offsetof(struct switch_stack, r20)); + DEFINE(SW_R21, offsetof(struct switch_stack, r21)); + DEFINE(SW_R22, offsetof(struct switch_stack, r22)); + DEFINE(SW_R23, offsetof(struct switch_stack, r23)); + DEFINE(SW_FP, offsetof(struct switch_stack, fp)); + DEFINE(SW_GP, offsetof(struct switch_stack, gp)); + DEFINE(SW_RA, offsetof(struct switch_stack, ra)); + DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack)); + + DEFINE(PS_S_ASM, PS_S); + + DEFINE(NIOS2_STATUS_PIE_MSK_ASM, NIOS2_STATUS_PIE_MSK); + DEFINE(NIOS2_STATUS_PIE_OFST_ASM, NIOS2_STATUS_PIE_OFST); + DEFINE(NIOS2_STATUS_U_MSK_ASM, NIOS2_STATUS_U_MSK); + DEFINE(NIOS2_STATUS_U_OFST_ASM, NIOS2_STATUS_U_OFST); + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* Offsets in thread_info structure, used in assembly code */ + DEFINE(TI_TASK, offsetof(struct thread_info, task)); + DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); + DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); + DEFINE(TI_PREEMPT_COUNT, offsetof(struct thread_info, preempt_count)); + + DEFINE(PREEMPT_ACTIVE_ASM, PREEMPT_ACTIVE); + + DEFINE(THREAD_SIZE_ASM, THREAD_SIZE); + + DEFINE(TIF_SYSCALL_TRACE_ASM, TIF_SYSCALL_TRACE); + DEFINE(TIF_NOTIFY_RESUME_ASM, TIF_NOTIFY_RESUME); + DEFINE(TIF_SIGPENDING_ASM, TIF_SIGPENDING); + DEFINE(TIF_NEED_RESCHED_ASM, TIF_NEED_RESCHED); + DEFINE(TIF_POLLING_NRFLAG_ASM, TIF_POLLING_NRFLAG); + + DEFINE(_TIF_SYSCALL_TRACE_ASM, _TIF_SYSCALL_TRACE); + DEFINE(_TIF_NOTIFY_RESUME_ASM, _TIF_NOTIFY_RESUME); + DEFINE(_TIF_SIGPENDING_ASM, _TIF_SIGPENDING); + DEFINE(_TIF_NEED_RESCHED_ASM, _TIF_NEED_RESCHED); + DEFINE(_TIF_POLLING_NRFLAG_ASM, _TIF_POLLING_NRFLAG); + + DEFINE(_TIF_WORK_MASK_ASM, _TIF_WORK_MASK); + +#if defined(na_flash_kernel) && defined(na_flash_kernel_end) + /* the flash chip */ + DEFINE(NIOS_FLASH_START, na_flash_kernel); + DEFINE(NIOS_FLASH_END, na_flash_kernel_end); + + /* the kernel placement in the flash*/ + DEFINE(KERNEL_FLASH_START, na_flash_kernel); + DEFINE(KERNEL_FLASH_LEN, 0x200000); + + /* the romdisk placement in the flash */ + DEFINE(LINUX_ROMFS_START, na_flash_kernel+0x200000); + DEFINE(LINUX_ROMFS_END, na_flash_kernel_end); +#else +#error Sorry,you dont have na_flash_kernel or na_flash_kernel_end defined in the core. +#endif + +#if defined(nasys_program_mem) && defined(nasys_program_mem_end) + /* the sdram */ + DEFINE(LINUX_SDRAM_START, nasys_program_mem); + DEFINE(LINUX_SDRAM_END, nasys_program_mem_end); +#else +#error Sorry,you dont have nasys_program_mem or nasys_program_mem_end defined in the core. +#endif + + DEFINE(NIOS2_ICACHE_SIZE, nasys_icache_size); + DEFINE(NIOS2_ICACHE_LINE_SIZE, nasys_icache_line_size); + DEFINE(NIOS2_DCACHE_SIZE, nasys_dcache_size); + DEFINE(NIOS2_DCACHE_LINE_SIZE, nasys_dcache_line_size); + +#if defined(na_enet) + DEFINE(NA_ENET_ASM, na_enet); +#endif + +#if defined(na_enet_reset) + DEFINE(NA_ENET_RESET_ASM, na_enet_reset); +#endif + +#if defined(na_enet_reset_n) + DEFINE(NA_ENET_RESET_N_ASM, na_enet_reset_n); +#endif + +#if defined(na_ide_interface) + DEFINE(NA_IDE_INTERFACE_ASM, na_ide_interface); +#endif + +#if defined(na_timer0) + DEFINE(NA_TIMER0_ASM, na_timer0); + DEFINE(NP_TIMERCONTROL_ASM, offsetof(np_timer, np_timercontrol)); + DEFINE(NP_TIMERSTATUS_ASM, offsetof(np_timer, np_timerstatus)); +#endif + +#if defined(na_uart0) + DEFINE(NA_UART0_ASM, na_uart0); + DEFINE(NP_UARTCONTROL_ASM, offsetof(np_uart, np_uartcontrol)); + DEFINE(NP_UARTSTATUS_ASM, offsetof(np_uart, np_uartstatus)); +#endif + +#if defined(na_uart1) + DEFINE(NA_UART1_ASM, na_uart1); +#endif + +#if defined(na_uart2) + DEFINE(NA_UART2_ASM, na_uart2); +#endif + +#if defined(na_uart3) + DEFINE(NA_UART3_ASM, na_uart3); +#endif + + return 0; +} diff --git a/arch/nios2nommu/kernel/dma.c b/arch/nios2nommu/kernel/dma.c new file mode 100644 index 00000000..f23323b0 --- /dev/null +++ b/arch/nios2nommu/kernel/dma.c @@ -0,0 +1,342 @@ +/* + * arch/nios2nommu/kernel/dma.c + * + * Copyright (C) 2005 Microtronix Datacom Ltd + * + * PC like DMA API for Nios's DMAC. + * + * 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 Wentao Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* nios2 dma controller register map */ +#define REG_DMA_STATUS 0 +#define REG_DMA_READADDR 4 +#define REG_DMA_WRITEADDR 8 +#define REG_DMA_LENGTH 12 +#define REG_DMA_CONTROL 24 + +/* status register bits definition */ +#define ST_DONE 0x01 +#define ST_BUSY 0x02 +#define ST_REOP 0x04 +#define ST_WROP 0x08 +#define ST_LEN 0x10 + +/* control register bits definition */ +#define CT_BYTE 0x01 +#define CT_HW 0x02 +#define CT_WORD 0x04 +#define CT_GO 0x08 +#define CT_IEEN 0x10 +#define CT_REEN 0x20 +#define CT_WEEN 0x40 +#define CT_LEEN 0x80 +#define CT_RCON 0x100 +#define CT_WCON 0x200 +#define CT_DOUBLE 0x400 +#define CT_QUAD 0x800 + +struct dma_channel { + unsigned int addr; /* control address */ + unsigned int irq; /* interrupt number */ + atomic_t idle; + unsigned int mode; /* dma mode: width, stream etc */ + int (*handler)(void*, int ); + void* user; + + char id[16]; + char dev_id[16]; +}; +static struct dma_channel dma_channels[]={ +#ifdef na_dma_0 + { + .addr = na_dma_0, + .irq = na_dma_0_irq, + .idle = ATOMIC_INIT(1), + }, +#endif +#ifdef na_dma_1 + { + .addr = na_dma_1, + .irq = na_dma_1_irq, + .idle = ATOMIC_INIT(1), + }, +#endif +}; +#define MAX_DMA_CHANNELS sizeof(dma_channels)/sizeof(struct dma_channel) + +void enable_dma(unsigned int dmanr) +{ + if (dmanr < MAX_DMA_CHANNELS) { + unsigned int ctl = dma_channels[dmanr].mode; + ctl |= CT_GO | CT_IEEN; + outl(ctl, dma_channels[dmanr].addr+REG_DMA_CONTROL); + } +} + +void disable_dma(unsigned int dmanr) +{ + if (dmanr < MAX_DMA_CHANNELS) { + unsigned int ctl = dma_channels[dmanr].mode; + ctl &= ~(CT_GO | CT_IEEN); + outl(ctl, dma_channels[dmanr].addr+REG_DMA_CONTROL); + } +} + +void set_dma_count(unsigned int dmanr, unsigned int count) +{ + if (dmanr < MAX_DMA_CHANNELS) { + dma_channels[dmanr].mode |= CT_LEEN; + outl(count, dma_channels[dmanr].addr+REG_DMA_LENGTH); + } +} + +int get_dma_residue(unsigned int dmanr) +{ + int result =-1; + if (dmanr < MAX_DMA_CHANNELS) { + result = inl(dma_channels[dmanr].addr+REG_DMA_LENGTH); + } + return result; +} + +int request_dma(unsigned int chan, const char *dev_id) +{ + struct dma_channel *channel; + + if ( chan >= MAX_DMA_CHANNELS) { + return -EINVAL; + } + + channel = &dma_channels[chan]; + + if (!atomic_dec_and_test(&channel->idle)) { + return -EBUSY; + } + + strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); + channel->handler=NULL; + channel->user=NULL; + channel->mode =0; + + return 0; +} + +void free_dma(unsigned int chan) +{ + if ( chan < MAX_DMA_CHANNELS) { + dma_channels[chan].handler=NULL; + dma_channels[chan].user=NULL; + atomic_set(&dma_channels[chan].idle, 1); + } +} + +int nios2_request_dma(const char *dev_id) +{ + int chann; + + for ( chann=0; chann < MAX_DMA_CHANNELS; chann++) { + if (request_dma(chann, dev_id)==0) + return chann; + } + + return -EINVAL; +} +void nios2_set_dma_handler(unsigned int dmanr, int (*handler)(void*, int), void* user) +{ + if (dmanr < MAX_DMA_CHANNELS) { + dma_channels[dmanr].handler=handler; + dma_channels[dmanr].user=user; + } +} +#define NIOS2_DMA_WIDTH_MASK (CT_BYTE | CT_HW | CT_WORD | CT_DOUBLE | CT_QUAD) +#define NIOS2_MODE_MASK (NIOS2_DMA_WIDTH_MASK | CT_REEN | CT_WEEN | CT_LEEN | CT_RCON | CT_WCON) +void nios2_set_dma_data_width(unsigned int dmanr, unsigned int width) +{ + if (dmanr < MAX_DMA_CHANNELS) { + dma_channels[dmanr].mode &= ~NIOS2_DMA_WIDTH_MASK; + switch (width) { + case 1: + dma_channels[dmanr].mode |= CT_BYTE; + break; + case 2: + dma_channels[dmanr].mode |= CT_HW; + break; + case 8: + dma_channels[dmanr].mode |= CT_DOUBLE; + break; + case 16: + dma_channels[dmanr].mode |= CT_QUAD; + break; + case 4: + default: + dma_channels[dmanr].mode |= CT_WORD; + break; + } + } +} + +void nios2_set_dma_rcon(unsigned int dmanr,unsigned int set) +{ + if (dmanr < MAX_DMA_CHANNELS) { + dma_channels[dmanr].mode &= ~(CT_REEN | CT_RCON); + if (set) + dma_channels[dmanr].mode |= (CT_REEN | CT_RCON); + } +} +void nios2_set_dma_wcon(unsigned int dmanr,unsigned int set) +{ + if (dmanr < MAX_DMA_CHANNELS) { + dma_channels[dmanr].mode &= ~(CT_WEEN | CT_WCON); + if (set) + dma_channels[dmanr].mode |= (CT_WEEN | CT_WCON); + } +} +void nios2_set_dma_mode(unsigned int dmanr, unsigned int mode) +{ + if (dmanr < MAX_DMA_CHANNELS) { + /* set_dma_mode is only allowed to change the bus width, + stream setting, etc. + */ + mode &= NIOS2_MODE_MASK; + dma_channels[dmanr].mode &= ~NIOS2_MODE_MASK; + dma_channels[dmanr].mode |= mode; + } +} + +void nios2_set_dma_raddr(unsigned int dmanr, unsigned int a) +{ + if (dmanr < MAX_DMA_CHANNELS) { + outl(a, dma_channels[dmanr].addr+REG_DMA_READADDR); + } +} +void nios2_set_dma_waddr(unsigned int dmanr, unsigned int a) +{ + if (dmanr < MAX_DMA_CHANNELS) { + outl(a, dma_channels[dmanr].addr+REG_DMA_WRITEADDR); + } +} + + +static irqreturn_t dma_isr(int irq, void *dev_id) +{ + struct dma_channel *chann=(struct dma_channel*)dev_id; + + if (chann) { + int status = inl(chann->addr+REG_DMA_STATUS); + /* ack the interrupt, and clear the DONE bit */ + outl(0, chann->addr+REG_DMA_STATUS); + /* call the peripheral callback */ + if (chann->handler) + chann->handler(chann->user, status); + } + + return IRQ_HANDLED; +} + + + +#ifdef CONFIG_PROC_FS +static int proc_dma_show(struct seq_file *m, void *v) +{ + int i; + + for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { + if (!atomic_read(&dma_channels[i].idle)) { + seq_printf(m, "%2d: %s\n", i, + dma_channels[i].dev_id); + } + } + return 0; +} + +static int proc_dma_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_dma_show, NULL); +} +static struct file_operations proc_dma_operations = { + .open = proc_dma_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_dma_init(void) +{ + struct proc_dir_entry *e; + + e = create_proc_entry("dma", 0, NULL); + if (e) + e->proc_fops = &proc_dma_operations; + + return 0; +} + +__initcall(proc_dma_init); + +#endif /* CONFIG_PROC_FS */ + +int __init init_dma(void) +{ + int i; + + for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { + sprintf(dma_channels[i].id, "dmac-%d", i); + /* disable the dmac channel */ + disable_dma(i); + /* request irq*/ + if (request_irq(dma_channels[i].irq, dma_isr, 0, dma_channels[i].id, (void*)&dma_channels[i])){ + printk("DMA controller %d failed to get irq %d\n", i, dma_channels[i].irq); + atomic_set(&dma_channels[i].idle, 0); + } + } + return 0; +} + +static void __exit exit_dma(void) +{ + int i; + + for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { + /* disable the dmac channel */ + disable_dma(i); + free_irq(dma_channels[i].irq, dma_channels[i].id); + } +} + +module_init(init_dma); +module_exit(exit_dma); + +MODULE_LICENSE("GPL"); + +//EXPORT_SYMBOL(claim_dma_lock); +//EXPORT_SYMBOL(release_dma_lock); +EXPORT_SYMBOL(enable_dma); +EXPORT_SYMBOL(disable_dma); +EXPORT_SYMBOL(set_dma_count); +EXPORT_SYMBOL(get_dma_residue); +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); +EXPORT_SYMBOL(nios2_request_dma); +EXPORT_SYMBOL(nios2_set_dma_handler); +EXPORT_SYMBOL(nios2_set_dma_data_width); +EXPORT_SYMBOL(nios2_set_dma_rcon); +EXPORT_SYMBOL(nios2_set_dma_wcon); +EXPORT_SYMBOL(nios2_set_dma_mode); +EXPORT_SYMBOL(nios2_set_dma_raddr); +EXPORT_SYMBOL(nios2_set_dma_waddr); + diff --git a/arch/nios2nommu/kernel/entry.S b/arch/nios2nommu/kernel/entry.S new file mode 100644 index 00000000..7f71a017 --- /dev/null +++ b/arch/nios2nommu/kernel/entry.S @@ -0,0 +1,898 @@ +/* + * linux/arch/nios2nommu/kernel/entry.S + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * Based on: + * + * linux/arch/m68knommu/kernel/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * ColdFire support by Greg Ungerer (gerg@snapgear.com) + * 5307 fixes by David W. Miller + * linux 2.4 support David McCullough + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +.text +.set noat +.set nobreak + +ENTRY(system_call) +/* SAVE_ALL */ + rdctl r10,status /* enable intrs again */ + ori r10,r10,0x0001 + wrctl status,r10 + + movi r2,-LENOSYS + stw r2,PT_R2(sp) /* default return value in r2 */ + /* original r2 is in orig_r2 */ + + movui r1,NR_syscalls + bgtu r3,r1,ret_from_exception + slli r1,r3,2 + movhi r11,%hiadj(sys_call_table) + add r1,r1,r11 + ldw r1,%lo(sys_call_table)(r1) + beq r1,r0,ret_from_exception + + movi r11,%lo(0xffffe000) /* Get thread info pointer */ + and r11,sp,r11 + ldw r11,TI_FLAGS(r11) + BTBNZ r11,r11,TIF_SYSCALL_TRACE_ASM,1f + + callr r1 + stw r2,PT_R2(sp) /* save the return value */ + br ret_from_exception +1: + SAVE_SWITCH_STACK + call syscall_trace + RESTORE_SWITCH_STACK + /* wentao: restore r4-9, since they are trashed by syscall_trace */ + ldw r4,PT_R4(sp) + ldw r5,PT_R5(sp) + ldw r6,PT_R6(sp) + ldw r7,PT_R7(sp) + ldw r8,PT_R8(sp) + ldw r9,PT_R9(sp) + callr r1 + stw r2,PT_R2(sp) /* save the return value */ + SAVE_SWITCH_STACK + call syscall_trace + RESTORE_SWITCH_STACK + +ret_from_exception: + ldw r1,PT_STATUS_EXTENSION(sp) /* check if returning to kernel */ + TSTBZ r1,r1,PS_S_ASM,Luser_return /* if so, skip resched, signals */ + +restore_all: + rdctl r10,status /* disable intrs */ + andi r10,r10,0xfffe + wrctl status, r10 + RESTORE_ALL + eret + +Luser_return: + GET_THREAD_INFO r24 /* get thread_info pointer */ + ldw r10,TI_FLAGS(r24) /* get thread_info->flags */ + ANDI32 r11,r10,_TIF_WORK_MASK_ASM + beq r11,r0,restore_all /* Nothing to do */ + BTBZ r1,r10,TIF_NEED_RESCHED_ASM,Lsignal_return + +Lwork_resched: + call schedule + br ret_from_exception + +Lsignal_return: + BTBZ r1,r10,TIF_SIGPENDING_ASM,restore_all + mov r5,sp /* pt_regs */ + SAVE_SWITCH_STACK + CLR r4 /* oldset = 0 */ + call do_signal + RESTORE_SWITCH_STACK + br restore_all + +/* + * Handle software exceptions. Put here so external interrupts + * can fall throught to ret_from_interrupt. + */ + +software_exception: + ldw r24,-4(ea) // instruction that caused the exception + xorhi r24,r24,0x003b // upper half of trap opcode + xori r24,r24,0x683a // lower half of trap opcode + bne r24,r0,instruction_trap /* N - check for instruction trap */ + cmpeqi r11,r2,TRAP_ID_SYSCALL /* ? Is this a syscall */ + bne r11,r0,system_call /* Y - handle syscall */ + cmpeqi r11,r2,TRAP_ID_APPDEBUG /* ? Is this an application debug */ + bne r11,r0,app_debug /* Y - handle app_debug */ + cmpeqi r11,r2,63 /* ? Is this the old syscall number */ + bne r11,r0,system_call /* Y - handle syscall to catch older apps*/ + br restore_all /* N - everything else is ignored for now */ + +app_debug: + GET_THREAD_INFO r24 /* get thread_info */ + ldw r1,TI_TASK(r24) /* get thread_info->task */ + ldw r24,(TASK_THREAD + THREAD_FLAGS)(r1) /* get thread_info->task->thread.flags */ + ORI32 r24, r24, NIOS2_FLAG_DEBUG /* set the debug flag */ + stw r24,(TASK_THREAD + THREAD_FLAGS)(r1) /* save thread_info->task->thread.flags */ + br restore_all + +/* + * This is the generic interrupt handler (for all hardware interrupt + * sources). It figures out the vector number and calls the appropriate + * interrupt service routine directly. + */ +ENTRY(inthandler) + SAVE_ALL + /* + * Test to see if the exception was a software exception or caused by an + * external interrupt, and vector accordingly. + */ + + rdctl r24,estatus + andi r24,r24,1 + beq r24,r0,software_exception + rdctl r12,ipending + beq r12,r0,software_exception + + movi r24,-1 + stw r24,PT_ORIG_R2(sp) + + /* + * Process an external hardware interrupt. + */ + + addi ea,ea,-4 /* re-issue the interrupted instruction */ + stw ea,PT_EA(sp) + rdctl r9,ienable /* Isolate possible interrupts */ + and r12,r12,r9 + beq r12,r0,ret_from_interrupt /* No one to service done */ + movi r4,%lo(-1) /* Start from bit position 0, highest priority */ + /* This is the IRQ # for handler call */ +1: addi r4,r4,1 + srl r10,r12,r4 + andi r10,r10,1 /* Isolate bit we are interested in */ + cmpeqi r11,r4,32 /* ? End of the register */ + bne r11,r0,ret_from_interrupt /* Y - out of here */ + beq r10,r0,1b + mov r5,sp /* Setup pt_regs pointer for handler call */ + PUSH r4 /* Save state for return */ + PUSH r12 + call process_int + POP r12 + POP r4 + br 1b /* Check for other interrupts while here */ + +ENTRY(ret_from_interrupt) + ldw r4,PT_STATUS_EXTENSION(sp) + TSTBZ r4,r4,PS_S_ASM,Luser_return // Returning to user + +#ifdef CONFIG_PREEMPT + GET_THREAD_INFO r1 + ldw r4,TI_PREEMPT_COUNT(r1) + bne r4,r0,restore_all + +need_resched: + ldw r4,TI_FLAGS(r1) // ? Need resched set + BTBZ r10,r4,TIF_NEED_RESCHED_ASM,restore_all + ldw r4,PT_ESTATUS(sp) // ? Interrupts off + BTBZ r10,r4,NIOS2_STATUS_PIE_OFST_ASM,restore_all + movia r4,PREEMPT_ACTIVE_ASM + stw r4,TI_PREEMPT_COUNT(r1) + rdctl r10,status /* enable intrs again */ + ori r10,r10,0x0001 + wrctl status,r10 + PUSH r1 + call schedule + POP r1 + mov r4,r0 + stw r4,TI_PREEMPT_COUNT(r1) + rdctl r10,status /* disable intrs */ + andi r10,r10,0xfffe + wrctl status, r10 + br need_resched +#else + br restore_all +#endif + + +/* + * Beware - when entering resume, prev (the current task) is + * in r4, next (the new task) is in r5, don't change these + * registers. + */ +ENTRY(resume) + + rdctl r7,status /* save thread status reg */ + stw r7,TASK_THREAD+THREAD_KPSR(r4) + + andi r7,r7,0x0fffe /* disable interrupts */ + wrctl status,r7 + + movia r8,status_extension /* save status extension */ + ldw r7,0(r8) + stw r7,TASK_THREAD+THREAD_KESR(r4) + + SAVE_SWITCH_STACK + stw sp,TASK_THREAD+THREAD_KSP(r4) /* save kernel stack pointer */ + ldw sp,TASK_THREAD+THREAD_KSP(r5) /* restore new thread stack */ + movia r24,_current_thread /* save thread */ + GET_THREAD_INFO r1 + stw r1,0(r24) + RESTORE_SWITCH_STACK + + ldw r7,TASK_THREAD+THREAD_KESR(r5) /* restore extended status reg */ + stw r7,0(r8) + + ldw r7,TASK_THREAD+THREAD_KPSR(r5) /* restore thread status reg */ + wrctl status,r7 + ret + +ENTRY(ret_from_fork) + call schedule_tail + br ret_from_exception + +ENTRY(sys_fork) + mov r4,sp + SAVE_SWITCH_STACK + call nios2_vfork + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_vfork) + mov r4,sp + SAVE_SWITCH_STACK + call nios2_vfork + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_execve) + mov r4,sp + SAVE_SWITCH_STACK + call nios2_execve + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_clone) + mov r4,sp + SAVE_SWITCH_STACK + call nios2_clone + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_sigsuspend) + mov r4,sp + SAVE_SWITCH_STACK + call do_sigsuspend + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_rt_sigsuspend) + mov r4,sp + SAVE_SWITCH_STACK + call do_rt_sigsuspend + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_sigreturn) + mov r4,sp + SAVE_SWITCH_STACK + call do_sigreturn + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_sigaltstack) + ldw r4,PT_R4(sp) + ldw r5,PT_R5(sp) + ldw r6,PT_SP(sp) + SAVE_SWITCH_STACK + call do_sigaltstack + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + call do_rt_sigreturn + RESTORE_SWITCH_STACK + ret + +/****************************************************************************** +* * +* License Agreement * +* * +* Copyright (c) 2003 Altera Corporation, San Jose, California, USA. * +* All rights reserved. * +* * +* Permission is hereby granted, free of charge, to any person obtaining a * +* copy of this software and associated documentation files (the "Software"), * +* to deal in the Software without restriction, including without limitation * +* the rights to use, copy, modify, merge, publish, distribute, sublicense, * +* and/or sell copies of the Software, and to permit persons to whom the * +* Software is furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in * +* all copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * +* DEALINGS IN THE SOFTWARE. * +* * +* This agreement shall be governed in all respects by the laws of the State * +* of California and by the laws of the United States of America. * +* * +******************************************************************************/ + + /* + * This is the software exception handler for Nios2. + */ + + /* + * Explicitly allow the use of r1 (the assembler temporary register) + * within this code. This register is normally reserved for the use of + * the compiler. + */ + +ENTRY(instruction_trap) + RESTORE_ALL // Clean off our save & setup for emulation + + /* INSTRUCTION EMULATION + * --------------------- + * + * Nios II processors generate exceptions for unimplemented instructions. + * The routines below emulate these instructions. Depending on the + * processor core, the only instructions that might need to be emulated + * are div, divu, mul, muli, mulxss, mulxsu, and mulxuu. + * + * The emulations match the instructions, except for the following + * limitations: + * + * 1) The emulation routines do not emulate the use of the exception + * temporary register (et) as a source operand because the exception + * handler already has modified it. + * + * 2) The routines do not emulate the use of the stack pointer (sp) or the + * exception return address register (ea) as a destination because + * modifying these registers crashes the exception handler or the + * interrupted routine. + * + * Detailed Design + * --------------- + * + * The emulation routines expect the contents of integer registers r0-r31 + * to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp). The + * routines retrieve source operands from the stack and modify the + * destination register's value on the stack prior to the end of the + * exception handler. Then all registers except the destination register + * are restored to their previous values. + * + * The instruction that causes the exception is found at address -4(ea). + * The instruction's OP and OPX fields identify the operation to be + * performed. + * + * One instruction, muli, is an I-type instruction that is identified by + * an OP field of 0x24. + * + * muli AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24- + * 27 22 6 0 <-- LSB of field + * + * The remaining emulated instructions are R-type and have an OP field + * of 0x3a. Their OPX fields identify them. + * + * R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a- + * 27 22 17 11 6 0 <-- LSB of field + * + * + * Opcode Encoding. muli is identified by its OP value. Then OPX & 0x02 + * is used to differentiate between the division opcodes and the remaining + * multiplication opcodes. + * + * Instruction OP OPX OPX & 0x02 + * ----------- ---- ---- ---------- + * muli 0x24 + * divu 0x3a 0x24 0 + * div 0x3a 0x25 0 + * mul 0x3a 0x27 != 0 + * mulxuu 0x3a 0x07 != 0 + * mulxsu 0x3a 0x17 != 0 + * mulxss 0x3a 0x1f != 0 + */ + + + /* + * Save everything on the stack to make it easy for the emulation routines + * to retrieve the source register operands. + */ + + addi sp, sp, -128 + stw zero, 0(sp) // Save zero on stack to avoid special case for r0. + stw r1, 4(sp) + stw r2, 8(sp) + stw r3, 12(sp) + stw r4, 16(sp) + stw r5, 20(sp) + stw r6, 24(sp) + stw r7, 28(sp) + stw r8, 32(sp) + stw r9, 36(sp) + stw r10, 40(sp) + stw r11, 44(sp) + stw r12, 48(sp) + stw r13, 52(sp) + stw r14, 56(sp) + stw r15, 60(sp) + stw r16, 64(sp) + stw r17, 68(sp) + stw r18, 72(sp) + stw r19, 76(sp) + stw r20, 80(sp) + stw r21, 84(sp) + stw r22, 88(sp) + stw r23, 92(sp) + // Don't bother to save et. It's already been changed. + stw bt, 100(sp) + stw gp, 104(sp) + stw sp, 108(sp) + stw fp, 112(sp) + // Don't bother to save ea. It's already been changed. + stw ba, 120(sp) + stw ra, 124(sp) + + + /* + * Split the instruction into its fields. We need 4*A, 4*B, and 4*C as + * offsets to the stack pointer for access to the stored register values. + */ + ldw r2,-4(ea) // r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP + roli r3,r2,7 // r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB + roli r4,r3,3 // r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB + roli r5,r4,2 // r5 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II + srai r4,r4,16 // r4 = (sign-extended) IMM16 + roli r6,r5,5 // r6 = XXXX,NNNNN,PPPPPP,AAAAA,BBBBB,CCCCC,XX + andi r2,r2,0x3f // r2 = 00000000000000000000000000,PPPPPP + andi r3,r3,0x7c // r3 = 0000000000000000000000000,AAAAA,00 + andi r5,r5,0x7c // r5 = 0000000000000000000000000,BBBBB,00 + andi r6,r6,0x7c // r6 = 0000000000000000000000000,CCCCC,00 + + /* Now + * r2 = OP + * r3 = 4*A + * r4 = IMM16 (sign extended) + * r5 = 4*B + * r6 = 4*C + */ + + + /* + * Get the operands. + * + * It is necessary to check for muli because it uses an I-type instruction + * format, while the other instructions are have an R-type format. + * + * Prepare for either multiplication or division loop. + * They both loop 32 times. + */ + movi r14,32 + + add r3,r3,sp // r3 = address of A-operand. + ldw r3,0(r3) // r3 = A-operand. + movi r7,0x24 // muli opcode (I-type instruction format) + beq r2,r7,mul_immed // muli doesn't use the B register as a source + + add r5,r5,sp // r5 = address of B-operand. + ldw r5,0(r5) // r5 = B-operand. + // r4 = SSSSSSSSSSSSSSSS,-----IMM16------ + // IMM16 not needed, align OPX portion + // r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000 + srli r4,r4,5 // r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX-- + andi r4,r4,0x3f // r4 = 00000000000000000000000000,-OPX-- + + /* Now + * r2 = OP + * r3 = src1 + * r5 = src2 + * r4 = OPX (no longer can be muli) + * r6 = 4*C + */ + + + + /* + * Multiply or Divide? + */ + andi r7,r4,0x02 // For R-type multiply instructions, OPX & 0x02 != 0 + bne r7,zero,multiply + + + /* DIVISION + * + * Divide an unsigned dividend by an unsigned divisor using + * a shift-and-subtract algorithm. The example below shows + * 43 div 7 = 6 for 8-bit integers. This classic algorithm uses a + * single register to store both the dividend and the quotient, + * allowing both values to be shifted with a single instruction. + * + * remainder dividend:quotient + * --------- ----------------- + * initialize 00000000 00101011: + * shift 00000000 0101011:_ + * remainder >= divisor? no 00000000 0101011:0 + * shift 00000000 101011:0_ + * remainder >= divisor? no 00000000 101011:00 + * shift 00000001 01011:00_ + * remainder >= divisor? no 00000001 01011:000 + * shift 00000010 1011:000_ + * remainder >= divisor? no 00000010 1011:0000 + * shift 00000101 011:0000_ + * remainder >= divisor? no 00000101 011:00000 + * shift 00001010 11:00000_ + * remainder >= divisor? yes 00001010 11:000001 + * remainder -= divisor - 00000111 + * ---------- + * 00000011 11:000001 + * shift 00000111 1:000001_ + * remainder >= divisor? yes 00000111 1:0000011 + * remainder -= divisor - 00000111 + * ---------- + * 00000000 1:0000011 + * shift 00000001 :0000011_ + * remainder >= divisor? no 00000001 :00000110 + * + * The quotient is 00000110. + */ + +divide: + /* + * Prepare for division by assuming the result + * is unsigned, and storing its "sign" as 0. + */ + movi r17,0 + + + // Which division opcode? + xori r7,r4,0x25 // OPX of div + bne r7,zero,unsigned_division + + + /* + * OPX is div. Determine and store the sign of the quotient. + * Then take the absolute value of both operands. + */ + xor r17,r3,r5 // MSB contains sign of quotient + bge r3,zero,dividend_is_nonnegative + sub r3,zero,r3 // -r3 +dividend_is_nonnegative: + bge r5,zero,divisor_is_nonnegative + sub r5,zero,r5 // -r5 +divisor_is_nonnegative: + + +unsigned_division: + // Initialize the unsigned-division loop. + movi r13,0 // remainder = 0 + + /* Now + * r3 = dividend : quotient + * r4 = 0x25 for div, 0x24 for divu + * r5 = divisor + * r13 = remainder + * r14 = loop counter (already initialized to 32) + * r17 = MSB contains sign of quotient + */ + + + /* + * for (count = 32; count > 0; --count) + * { + */ +divide_loop: + + /* + * Division: + * + * (remainder:dividend:quotient) <<= 1; + */ + slli r13,r13,1 + cmplt r7,r3,zero // r7 = MSB of r3 + or r13,r13,r7 + slli r3,r3,1 + + + /* + * if (remainder >= divisor) + * { + * set LSB of quotient + * remainder -= divisor; + * } + */ + bltu r13,r5,div_skip + ori r3,r3,1 + sub r13,r13,r5 +div_skip: + + /* + * } + */ + subi r14,r14,1 + bne r14,zero,divide_loop + + + /* Now + * r3 = quotient + * r4 = 0x25 for div, 0x24 for divu + * r6 = 4*C + * r17 = MSB contains sign of quotient + */ + + + /* + * Conditionally negate signed quotient. If quotient is unsigned, + * the sign already is initialized to 0. + */ + bge r17,zero,quotient_is_nonnegative + sub r3,zero,r3 // -r3 +quotient_is_nonnegative: + + + /* + * Final quotient is in r3. + */ + add r6,r6,sp + stw r3,0(r6) // write quotient to stack + br restore_registers + + + + + /* MULTIPLICATION + * + * A "product" is the number that one gets by summing a "multiplicand" + * several times. The "multiplier" specifies the number of copies of the + * multiplicand that are summed. + * + * Actual multiplication algorithms don't use repeated addition, however. + * Shift-and-add algorithms get the same answer as repeated addition, and + * they are faster. To compute the lower half of a product (pppp below) + * one shifts the product left before adding in each of the partial products + * (a * mmmm) through (d * mmmm). + * + * To compute the upper half of a product (PPPP below), one adds in the + * partial products (d * mmmm) through (a * mmmm), each time following the + * add by a right shift of the product. + * + * mmmm + * * abcd + * ------ + * #### = d * mmmm + * #### = c * mmmm + * #### = b * mmmm + * #### = a * mmmm + * -------- + * PPPPpppp + * + * The example above shows 4 partial products. Computing actual Nios II + * products requires 32 partials. + * + * It is possible to compute the result of mulxsu from the result of mulxuu + * because the only difference between the results of these two opcodes is + * the value of the partial product associated with the sign bit of rA. + * + * mulxsu = mulxuu - (rA < 0) ? rB : 0; + * + * It is possible to compute the result of mulxss from the result of mulxsu + * because the only difference between the results of these two opcodes is + * the value of the partial product associated with the sign bit of rB. + * + * mulxss = mulxsu - (rB < 0) ? rA : 0; + * + */ + +mul_immed: + // Opcode is muli. Change it into mul for remainder of algorithm. + mov r6,r5 // Field B is dest register, not field C. + mov r5,r4 // Field IMM16 is src2, not field B. + movi r4,0x27 // OPX of mul is 0x27 + +multiply: + // Initialize the multiplication loop. + movi r9,0 // mul_product = 0 + movi r10,0 // mulxuu_product = 0 + mov r11,r5 // save original multiplier for mulxsu and mulxss + mov r12,r5 // mulxuu_multiplier (will be shifted) + movi r16,1 // used to create "rori B,A,1" from "ror B,A,r16" + + /* Now + * r3 = multiplicand + * r5 = mul_multiplier + * r6 = 4 * dest_register (used later as offset to sp) + * r7 = temp + * r9 = mul_product + * r10 = mulxuu_product + * r11 = original multiplier + * r12 = mulxuu_multiplier + * r14 = loop counter (already initialized) + * r16 = 1 + */ + + + /* + * for (count = 32; count > 0; --count) + * { + */ +multiply_loop: + + /* + * mul_product <<= 1; + * lsb = multiplier & 1; + */ + slli r9,r9,1 + andi r7,r12,1 + + /* + * if (lsb == 1) + * { + * mulxuu_product += multiplicand; + * } + */ + beq r7,zero,mulx_skip + add r10,r10,r3 + cmpltu r7,r10,r3 // Save the carry from the MSB of mulxuu_product. + ror r7,r7,r16 // r7 = 0x80000000 on carry, or else 0x00000000 +mulx_skip: + + /* + * if (MSB of mul_multiplier == 1) + * { + * mul_product += multiplicand; + * } + */ + bge r5,zero,mul_skip + add r9,r9,r3 +mul_skip: + + /* + * mulxuu_product >>= 1; logical shift + * mul_multiplier <<= 1; done with MSB + * mulx_multiplier >>= 1; done with LSB + */ + srli r10,r10,1 + or r10,r10,r7 // OR in the saved carry bit. + slli r5,r5,1 + srli r12,r12,1 + + + /* + * } + */ + subi r14,r14,1 + bne r14,zero,multiply_loop + + + /* + * Multiply emulation loop done. + */ + + /* Now + * r3 = multiplicand + * r4 = OPX + * r6 = 4 * dest_register (used later as offset to sp) + * r7 = temp + * r9 = mul_product + * r10 = mulxuu_product + * r11 = original multiplier + */ + + + // Calculate address for result from 4 * dest_register + add r6,r6,sp + + + /* + * Select/compute the result based on OPX. + */ + + + // OPX == mul? Then store. + xori r7,r4,0x27 + beq r7,zero,store_product + + // It's one of the mulx.. opcodes. Move over the result. + mov r9,r10 + + // OPX == mulxuu? Then store. + xori r7,r4,0x07 + beq r7,zero,store_product + + // Compute mulxsu + // + // mulxsu = mulxuu - (rA < 0) ? rB : 0; + // + bge r3,zero,mulxsu_skip + sub r9,r9,r11 +mulxsu_skip: + + // OPX == mulxsu? Then store. + xori r7,r4,0x17 + beq r7,zero,store_product + + // Compute mulxss + // + // mulxss = mulxsu - (rB < 0) ? rA : 0; + // + bge r11,zero,mulxss_skip + sub r9,r9,r3 +mulxss_skip: + // At this point, assume that OPX is mulxss, so store + + +store_product: + stw r9,0(r6) + + +restore_registers: + // No need to restore r0. + ldw r1, 4(sp) + ldw r2, 8(sp) + ldw r3, 12(sp) + ldw r4, 16(sp) + ldw r5, 20(sp) + ldw r6, 24(sp) + ldw r7, 28(sp) + ldw r8, 32(sp) + ldw r9, 36(sp) + ldw r10, 40(sp) + ldw r11, 44(sp) + ldw r12, 48(sp) + ldw r13, 52(sp) + ldw r14, 56(sp) + ldw r15, 60(sp) + ldw r16, 64(sp) + ldw r17, 68(sp) + ldw r18, 72(sp) + ldw r19, 76(sp) + ldw r20, 80(sp) + ldw r21, 84(sp) + ldw r22, 88(sp) + ldw r23, 92(sp) + ldw et, 96(sp) + ldw bt, 100(sp) + ldw gp, 104(sp) + // Don't corrupt sp. + ldw fp, 112(sp) + // Don't corrupt ea. + ldw ba, 120(sp) + ldw ra, 124(sp) + addi sp, sp, 128 + eret + +.set at +.set break + diff --git a/arch/nios2nommu/kernel/head.S b/arch/nios2nommu/kernel/head.S new file mode 100644 index 00000000..ba9ea125 --- /dev/null +++ b/arch/nios2nommu/kernel/head.S @@ -0,0 +1,228 @@ +/* + * head.S for Altera's Excalibur development board with nios processor + * + * (c) Vic Phillips, Microtronix Datacom Ltd., 2001 + * (C) Copyright 2004 Microtronix Datacom Ltd + * + * Based on the following from the Excalibur sdk distribution: + * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s + * + * 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., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + + +#ifdef CONFIG_CRC_CHECK +/**********************************************/ +/* Define where the CRC table lives in flash. */ +/* The __CRC_Sector_Size is the flash sector */ +/* size for the address range. */ +/**********************************************/ + + GEQU __CRC_Table_Begin,(na_flash)+0x4000 /* Second sector of main board flash */ + GEQU __CRC_Sector_Size,0x2000 +#endif + +/* + * This global variable is used as an extension to the nios' + * STATUS register to emulate a user/supervisor mode. + */ + .data + .align 2 + .set noat + .global status_extension +status_extension: + .long 0 + + .global _current_thread +_current_thread: + .long 0 +/* + * Input(s): passed from u-boot + * r4 - Optional pointer to a board information structure. + * r5 - Optional pointer to the physical starting address of the init RAM + * disk. + * r6 - Optional pointer to the physical ending address of the init RAM + * disk. + * r7 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + */ + +/* + * First executable code - detected and jumped to by the ROM bootstrap + * if the code resides in flash (looks for "Nios" at offset 0x0c from + * the potential executable image). + */ + .text + .global _start +_start: + wrctl status,r0 /* Disable interrupts */ + + /* Flush all cache lines within the instruction cache */ + + movia r1,NIOS2_ICACHE_SIZE + movui r2,NIOS2_ICACHE_LINE_SIZE + +text_flush: + flushi r1 + sub r1,r1,r2 + bgt r1,r0,text_flush + br 1f + + /* This is the default location for the exception + * handler. Code in jump to our handler + */ + + movia r24,inthandler + jmp r24 +1: + /* + * After flushing the instruction cache, we must flush the data + * cache. + */ + + movia r1,NIOS2_DCACHE_SIZE + movi r2,NIOS2_DCACHE_LINE_SIZE + +data_flush: + flushd 0(r1) + sub r1,r1,r2 + bgt r1,r0,data_flush + +NR_MoveStart: +#ifdef CONFIG_BREAK_ON_START + break +#endif //CONFIG_BREAK_ON_START + nextpc r1 /* Find out where we are */ +chkadr: + movia r2,chkadr + beq r1,r2,finish_move /* We are running in RAM done */ + addi r1,r1,(_start - chkadr) /* Source */ + movia r2,_start /* Destination */ + movia r3,__data_end /* End of copy */ + +loop_move: // r1: src, r2: dest, r3: last dest + ldw r8,0(r1) // load a word from [r1] + stw r8,0(r2) // stort a word to dest [r2] + flushd 0(r2) // Flush cache for safty + addi r1,r1,4 // inc the src addr + addi r2,r2,4 // inc the dest addr + blt r2,r3,loop_move + + movia r1,finish_move // VMA(_start)->l1 + jmp r1 // jmp to _start + +finish_move: + + //------------------------------------ + // Disable interrupts on known devices + // +#ifdef NA_ENET_ASM +#ifdef NA_ENET_RESET_ASM + movia r1,NA_ENET_RESET_ASM // ethernet reset address + stwio r0,0(r1) // reset +#endif +#ifdef NA_ENET_RESET_N_ASM + movia r1,NA_ENET_RESET_N_ASM // ethernet reset address + stwio r0,0(r1) // reset +#endif + nop // give it some time + nop // + nop // + nop // +#endif +#ifdef NA_TIMER0_ASM + movia r1,NA_TIMER0_ASM // get timer address + stwio r0,NP_TIMERCONTROL_ASM(r1) // clear interrupt enable + stwio r0,NP_TIMERSTATUS_ASM(r1) // clear interrupt condition +#endif +#ifdef NA_UART0_ASM + movia r1,NA_UART0_ASM + stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable + stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status +#endif +#ifdef NA_UART1_ASM + movia r1,NA_UART1_ASM + stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable + stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status +#endif +#ifdef NA_UART2_ASM + movia r1,NA_UART2_ASM + stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable + stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status +#endif +#ifdef NA_UART3_ASM + movia r1,NA_UART3_ASM + stwio r0,NP_UARTCONTROL_ASM(r1) // clear interrupt enable + stwio r0,NP_UARTSTATUS_ASM(r1) // clear interrupt status +#endif +#ifdef NA_IDE_INTERFACE_ASM + movia r1,NA_IDE_INTERFACE_ASM // ATA reset + stwio r0,0(r1) // write to control register +#endif +#ifdef NA_ENET_ASM +#ifdef NA_ENET_RESET_ASM + movia r1,NA_ENET_RESET_ASM // ethernet reset address + movui r2,1 // reset + stwio r2,0(r1) // +#endif +#ifdef NA_ENET_RESET_N_ASM + movia r1,NA_ENET_RESET_N_ASM // ethernet reset address + movui r2,1 // reset + stwio r2,0(r1) // +#endif +#endif + wrctl ienable,r0 // Mask off all possible interrupts + + //------------------------------------------------------ + // Zero out the .bss segment (uninitialized common data) + // + movia r2,__bss_start // presume nothing is between + movia r1,_end // the .bss and _end. +1: + stb r0,0(r2) + addi r2,r2,1 + bne r1,r2,1b + + //------------------------------------------------------ + // Call main() with interrupts disabled + // + movia r1,status_extension // get the STATUS extension address + movi r2,PS_S_ASM // set initial mode = supervisor + stw r2,0(r1) + + movia r1,init_thread_union // set stack at top of the task union + addi sp,r1,THREAD_SIZE_ASM + movia r2,_current_thread // Remember current thread + stw r1,0(r2) + + movia r1,nios2_boot_init // save args r4-r7 passed from u-boot + callr r1 + + movia r1,main // call main as a subroutine + callr r1 + + //------------------------------------------------------------------ + // If we return from main, break to the oci debugger and buggered we are + // + break + + /* End of startup code */ +.set at + + diff --git a/arch/nios2nommu/kernel/init_task.c b/arch/nios2nommu/kernel/init_task.c new file mode 100644 index 00000000..867e8fbc --- /dev/null +++ b/arch/nios2nommu/kernel/init_task.c @@ -0,0 +1,69 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/init_task.c + * + * Ported from arch/m68knommu/kernel/init_task.c + * + * Copyright (C) 2003, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +__asm__(".align 2"); +struct task_struct init_task = INIT_TASK(init_task); + + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + diff --git a/arch/nios2nommu/kernel/io.c b/arch/nios2nommu/kernel/io.c new file mode 100644 index 00000000..e1b0b129 --- /dev/null +++ b/arch/nios2nommu/kernel/io.c @@ -0,0 +1,143 @@ +/*-------------------------------------------------------------------- + * + * Optimized IO string functions. + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +void insl(unsigned long port, void *dst, unsigned long count) +{ + unsigned long read32; + + if ((unsigned long)dst & 2){ + /* Unaligned destination pointer, need to do + * two 16 bit writes for each read. + */ + unsigned short *p=(unsigned short*)dst; + while (count--){ + read32 = inl(port); + *p++ = read32 & 0xFFFF; + *p++ = read32 >> 16; + } + } + else { + unsigned long *p=(unsigned long*)dst; + while (count--) + *p++ = inl(port); + } +} + +void insw(unsigned long port, void *dst, unsigned long count) +{ + unsigned long dst1=(unsigned long)dst; + if (count > 8) { + /* Long word align buffer ptr */ + if (dst1 & 2) { + *(unsigned short*)dst1 = inw(port); + dst1 += sizeof(unsigned short); + count--; + } + + /* Input pairs of short and store as longs */ + while (count >= 8) { + *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); + *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); + *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); + *((unsigned long *)dst1) = inw(port) + (inw(port) << 16); dst1+=sizeof(unsigned long); + count -= 8; + } + } + + /* Input remaining shorts */ + while (count--) { + *((unsigned short *)dst1) = inw(port); + dst1 += sizeof(unsigned short); + } +} + + +void outsl(unsigned long port, void *src, unsigned long count) +{ + unsigned long src1=(unsigned long)src; + unsigned long write32; + + if (src1 & 2){ + /* Unaligned source pointer, need to read + * two 16 bit shorts before writing to register. + */ + while (count--){ + write32 = *(unsigned short *)src1; + src1+=sizeof(unsigned short); + write32 |= *((unsigned short *)src1) << 16; + src1+=sizeof(unsigned short); + outl(write32,port); + } + } + else { + while (count--) { + outl(*(unsigned long *)src1,port); + src1+=sizeof(unsigned long); + } + } +} + +void outsw(unsigned long port, void *src, unsigned long count) +{ + unsigned int lw; + unsigned long src1=(unsigned long)src; + + if (count > 8) { + /* Long word align buffer ptr */ + if (src1 & 2) { + outw( *(unsigned short *)src1, port ); + count--; + src1 += sizeof(unsigned short); + } + + /* Read long words and output as pairs of short */ + while (count >= 8) { + lw = *(unsigned long *)src1; + src1+=sizeof(unsigned long); + outw(lw, port); + outw((lw >> 16), port); + lw = *(unsigned long *)src1; + src1+=sizeof(unsigned long); + outw(lw, port); + outw((lw >> 16), port); + lw = *(unsigned long *)src1; + src1+=sizeof(unsigned long); + outw(lw, port); + outw((lw >> 16), port); + lw = *(unsigned long *)src1; + src1+=sizeof(unsigned long); + outw(lw, port); + outw((lw >> 16), port); + count -= 8; + } + } + + /* Output remaining shorts */ + while (count--) { + outw( *(unsigned short *)src1, port ); + src1 += sizeof(unsigned short); + } +} diff --git a/arch/nios2nommu/kernel/irq.c b/arch/nios2nommu/kernel/irq.c new file mode 100644 index 00000000..f1b23472 --- /dev/null +++ b/arch/nios2nommu/kernel/irq.c @@ -0,0 +1,245 @@ +/* + * linux/arch/$(ARCH)/irq.c -- general exception handling code + * + * Cloned from Linux/m68k. + * + * No original Copyright holder listed, + * Probabily original (C) Roman Zippel (assigned DJD, 1999) + * + * Copyright 1999-2000 D. Jeff Dionne, + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* table for system interrupt handlers */ +irq_hand_t irq_list[NR_IRQS]; + +/* The number of spurious interrupts */ +volatile unsigned int num_spurious; + +#define NUM_IRQ_NODES 16 +static irq_node_t nodes[NUM_IRQ_NODES]; + +void __init init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + +static irqreturn_t default_irq_handler(int irq, void *ptr) +{ +#if 1 + printk(KERN_INFO "%s(%d): default irq handler vec=%d [0x%x]\n", + __FILE__, __LINE__, irq, irq); +#endif + disable_irq(irq); + return(IRQ_NONE); +} + +/* + * void init_IRQ(void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ + +void __init init_IRQ(void) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_list[i].handler = default_irq_handler; + irq_list[i].flags = IRQ_FLG_STD; + irq_list[i].dev_id = NULL; + irq_list[i].devname = NULL; + } + + for (i = 0; i < NUM_IRQ_NODES; i++) + nodes[i].handler = NULL; + + /* turn off all interrupts */ + clrimr(0); + +#ifdef DEBUG + printk("init_IRQ done\n"); +#endif +} + +irq_node_t *new_irq_node(void) +{ + irq_node_t *node; + short i; + + for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) + if (!node->handler) + return node; + + printk (KERN_INFO "new_irq_node: out of nodes\n"); + return NULL; +} + +int request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long flags, + const char *devname, + void *dev_id) +{ + if (irq >= NR_IRQS) { + printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (!(irq_list[irq].flags & IRQ_FLG_STD)) { + if (irq_list[irq].flags & IRQ_FLG_LOCK) { + printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_list[irq].devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_list[irq].devname); + return -EBUSY; + } + } + irq_list[irq].handler = handler; + irq_list[irq].flags = flags; + irq_list[irq].dev_id = dev_id; + irq_list[irq].devname = devname; + + setimr(1<= NR_IRQS) { + printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_list[irq].dev_id != dev_id) + printk(KERN_ERR "%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_list[irq].devname); + + irq_list[irq].handler = default_irq_handler; + irq_list[irq].flags = IRQ_FLG_STD; + irq_list[irq].dev_id = NULL; + irq_list[irq].devname = NULL; + + clrimr(~(1< +*/ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: NO-ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + + +int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *mod) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + + DEBUGP ("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) { + /* This is where to make the change */ + uint32_t word; + uint32_t *loc + = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset); + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + Elf32_Sym *sym + = ((Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM (rela[i].r_info)); + uint32_t v = sym->st_value + rela[i].r_addend; + + switch (ELF32_R_TYPE (rela[i].r_info)) { + case R_NIOS2_NONE: + break; + + case R_NIOS2_BFD_RELOC_32: + *loc += v; + break; + + case R_NIOS2_PCREL16: + v -= (uint32_t)loc + 4; + if ((int32_t)v > 0x7fff || + (int32_t)v < -(int32_t)0x8000) { + printk(KERN_ERR + "module %s: relocation overflow\n", + mod->name); + return -ENOEXEC; + } + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f); + break; + + case R_NIOS2_CALL26: + if (v & 3) { + printk(KERN_ERR + "module %s: dangerous relocation\n", + mod->name); + return -ENOEXEC; + } + if ((v >> 28) != ((uint32_t)loc >> 28)) { + printk(KERN_ERR + "module %s: relocation overflow\n", + mod->name); + return -ENOEXEC; + } + *loc = (*loc & 0x3f) | ((v >> 2) << 6); + break; + + case R_NIOS2_HI16: + word = *loc; + *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) | + (word & 0x3f); + break; + + case R_NIOS2_LO16: + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + break; + + case R_NIOS2_HIADJ16: + { + Elf32_Addr word2; + + word = *loc; + word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; + *loc = ((((word >> 22) << 16) | word2) << 6) | + (word & 0x3f); + } + break; + + default: + printk (KERN_ERR "module %s: Unknown reloc: %u\n", + mod->name, ELF32_R_TYPE (rela[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/nios2nommu/kernel/nios2_ksyms.c b/arch/nios2nommu/kernel/nios2_ksyms.c new file mode 100644 index 00000000..1602b67a --- /dev/null +++ b/arch/nios2nommu/kernel/nios2_ksyms.c @@ -0,0 +1,124 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/nios_ksyms.c + * + * Derived from Nios1 + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * vic - copied from v850 + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +//;dgt2;tmp; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +/* platform dependent support */ + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strcpy); + +EXPORT_SYMBOL(kernel_thread); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memmove); + +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__up); + +EXPORT_SYMBOL(get_wchan); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __gcc_bcmp(void); +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __cmpdi2(void); +extern void __divdi3(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __moddi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __mulsi3(void); +extern void __negdi2(void); +extern void __ucmpdi2(void); +extern void __udivdi3(void); +extern void __udivmoddi4(void); +extern void __udivsi3(void); +extern void __umoddi3(void); +extern void __umodsi3(void); + + /* gcc lib functions */ +EXPORT_SYMBOL(__gcc_bcmp); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__cmpdi2); +EXPORT_SYMBOL(__divdi3); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__moddi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulsi3); +EXPORT_SYMBOL(__negdi2); +EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__udivdi3); +EXPORT_SYMBOL(__udivmoddi4); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umoddi3); +EXPORT_SYMBOL(__umodsi3); diff --git a/arch/nios2nommu/kernel/nios_gdb_stub.c b/arch/nios2nommu/kernel/nios_gdb_stub.c new file mode 100644 index 00000000..103925b6 --- /dev/null +++ b/arch/nios2nommu/kernel/nios_gdb_stub.c @@ -0,0 +1,1456 @@ +// Modified for uClinux - Vic - Apr 2002 +// From: + +// File: nios_gdb_stub.c +// Date: 2000 June 20 +// Author dvb \ Altera Santa Cruz + +#ifndef __KERNEL__ +#include "nios.h" +#else +#include +#include +#include +#endif + +#include "nios_gdb_stub.h" + +#define na_debug_peripheral_irq 8 + +enum +{ + na_BreakpointTrap = 3, + na_SingleStepTrap = 4, + na_StartGDBTrap = 5 +}; + + +#ifdef __KERNEL__ + +extern int _etext; + +static void puts( unsigned char *s ) +{ + while(*s) { + while (!(nasys_printf_uart->np_uartstatus & np_uartstatus_trdy_mask)); + nasys_printf_uart->np_uarttxdata = *s++; + } +} + +#endif // __KERNEL__ + +// -------------------------------- +// Local Prototypes + +#if GDB_DEBUG_PRINT + +static void StringFit(char *s,int w); + +// -------------------------------- +// Debugging The Debugger + +void GDB_RawMessage(char *s) + { + StringFit(s,32); + nr_pio_lcdwritescreen(s); + } +#else + #define GDB_RawMessage(a,b,c) // define away to nothing +#endif + +#if GDB_DEBUG_PRINT +void GDB_Print2(char *s,int n1,int n2) + { + char st[1000]; + + sprintf(st,s,n1,n2); + GDB_RawMessage(st); + } +#else + #define GDB_Print2(a,b,c) // define away to nothing +#endif + +// If string is longer than w, cut out the middle. + +#if GDB_DEBUG_PRINT +int StringLen(char *s) + { + int l = 0; + + while(*s++) + l++; + return l; + } + +static void StringFit(char *s,int w) + { + if(StringLen(s) > w) + { + int i; + + + w = w / 2; + + for(i = 0; i < w; i++) + { + s[i + w] = s[StringLen(s) - w + i]; + } + s[w + w] = 0; + } + } +#endif + +// --------------------------------------------- +// Generic routines for dealing with +// hex input, output, and parsing +// (Adapted from other stubs.) + +NiosGDBGlobals gdb = {0}; // not static: the ISR uses it! + +static char dHexChars[16] = "0123456789abcdef"; + +/* + * HexCharToValue -- convert a characters + * to its hex value, or -1 if not. + */ +char HexCharToValue(char c) +{ + char result=0; + + if(c >= '0' && c <= '9') + result = c - '0'; + else if(c >= 'a' && c <= 'f') + result = c - 'a' + 10; + else if(c >= 'A' && c <= 'F') + result = c - 'A' + 10; + else + result = -1; + return result; +} + +/* + * HexStringToValue -- convert a 2*byte_width string of characters + * to its little endian hex value, + * or -1 if not. + * This routine is for strings of hex values + */ +unsigned long HexStringToValue(char *c, int byte_width) +{ + unsigned long result=0; + unsigned char a,b; + int i=0; + + while (i < byte_width) + { + a = HexCharToValue(*c++); + if (a & 0x80) return a; + b = HexCharToValue(*c++); + if (b & 0x80) return b; + b = (a<<4) | (b&0x0f); + result |= b << (i*8); + i++; + } + return result; +} + +/* + * Hex2Value -- convert a non-hex char delimited string + * to its big endian hex value. + * This routine is for address and byte count values + */ + +char *Hex2Value(char *hexIn, int *valueOut) + { + char c; + int digitValue; + int value = 0; + + while(1) + { + c = *hexIn; + digitValue = HexCharToValue(c); + if(digitValue < 0) + { + *valueOut = value; + return hexIn; + } + hexIn++; + value = (value << 4) + digitValue; + } + } + +/* + * HexToMem -- convert a string to a specified + * number of bytes in memory. + * + * JMB -- make this thing a bit smarter so + * that it selects the byte width to + * write based on the number of bytes + * and the destination address alignment. + * This is to support writes to non-byte enabled + * peripheral registers...I don't like it. + * Beware! there are cases where it wont work + */ +char *HexToMem(char *hexIn, char *memOut, int memByteCount) +{ + int i; + unsigned long x; + short *memOutS=0; + long *memOutL=0; + int byte_width; + + //determine maximum byte width + if (((memByteCount%2) != 0) || (((unsigned int)memOut%2) != 0)) + byte_width = 1; + else if (((memByteCount % 4) != 0) || (((unsigned int)memOut % 4) != 0)) + { + byte_width = 2; + memOutS = (short *)memOut; + } + else + { + byte_width = 4; + memOutL = (long *)memOut; + } + for(i = 0; i < memByteCount; i+=byte_width) + { + x = HexStringToValue(hexIn,byte_width); + hexIn += byte_width*2; + switch (byte_width) + { + case 1: + *memOut++ = (unsigned char) 0x000000ff & x; + break; + case 2: + *memOutS++ = (unsigned short) 0x0000ffff & x; + break; + case 4: + *memOutL++ = x; + break; + default: + //How could this ever happen??? + break; + } + } + + return hexIn; +} + +char *MemToHex(char *memIn, char *hexOut, int memByteCount) +{ + int i,j; + int byte_width; + unsigned long x=0; + unsigned short *memInS=0; + unsigned long *memInL=0; + + //determine maximum byte width + if (((memByteCount % 2) != 0) || (((unsigned int)memIn % 2) != 0)) + byte_width = 1; + else if (((memByteCount % 4) != 0) || (((unsigned int)memIn % 4) != 0)) + { + byte_width = 2; + memInS = (short *)memIn; + } + else + { + byte_width = 4; + memInL = (long *)memIn; + } + + for(i = 0; i < memByteCount; i+=byte_width) + { + switch (byte_width) + { + case 1: + x = *memIn++; + break; + case 2: + x = *memInS++; + break; + case 4: + x = *memInL++; + break; + default: + //How would we get here? + break; + } + + for (j=0; j>4]; + *hexOut++ = dHexChars[x&0x0000000f]; + x = x>>8; + } + } + + *hexOut = 0; + + return hexOut; +} + +//Send just the + or - to indicate +//ACK or NACK +void GDBPutAck (char ack) +{ + if (gdb.comlink == ne_gdb_serial) + GDBPutChar (ack); +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + else + { + if (gdb.host_ip_address != 0) + nr_plugs_send_to (gdb.gdb_eth_plug, &ack, 1, 0, + gdb.host_ip_address, + gdb.host_port_number); + } +#endif +#endif +} + +/* + * Once a $ comes in, use GetGDBPacket to + * retrieve a full gdb packet, and verify + * checksum, and reply + or -. + */ +int GetGDBPacket(char *aBuffer) +{ + int checksum=0; + int length=0; + char c; + int x=0; + + if (gdb.comlink == ne_gdb_serial) + { + while ((c = GDBGetChar ()) != '$') ; + +startPacket: + length = 0; + checksum = 0; + while(((c = GDBGetChar()) != '#') && (length < kTextBufferSize)) + { + if(c == '$') + goto startPacket; + checksum += c; + aBuffer[length++] = c; + aBuffer[length] = 0; + } + + c = GDBGetChar(); + x = HexCharToValue(c) << 4; + c = GDBGetChar(); + x += HexCharToValue(c); + + + checksum &= 0xff; + + GDB_Print2("GetPacket %d",length,0); + } +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + else + { + int srcidx; + // wait till beginning of packet + while (gdb.textBuffer[0] != '$') nr_plugs_idle(); +startEPacket: + length = 0; + checksum = 0; + srcidx = 1; + + //loop until packet terminator + //leave enough room for the checksum at the end + while (((c = gdb.textBuffer[srcidx++]) != '#') && (srcidx < kTextBufferSize-2)) + { + if (c == '$') + goto startEPacket; + + checksum += c; + aBuffer[length++] = c; + } + + c = gdb.textBuffer[srcidx++]; + x = HexCharToValue(c) << 4; + c = gdb.textBuffer[srcidx++]; + x += HexCharToValue (c); + + aBuffer[length++] = 0; + + checksum &= 0xff; + + GDB_Print2("GetPacket %d",length,0); + } +#endif +#endif + + if(checksum != x) + { + GDBPutAck('-'); + length = 0; + } + else + { + GDBPutAck('+'); + } + return length; +} + +//Wait for acknowledgement +//Should we have some way of timing out??? +//return TRUE if ACK +//return FALSE if NACK +int GDBGetACK (void) +{ + char c; + if (gdb.comlink == ne_gdb_serial) + { + while (1) + { + c = GDBGetChar (); + if (c == '+') return (1); + else if (c == '-') return (0); + } + + } +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + else + { + gdb.ACKstatus = ne_gdb_ack_waiting; + while (1) + { + nr_plugs_idle (); + if (gdb.ACKstatus == ne_gdb_ack_acked) + { + gdb.ACKstatus = ne_gdb_ack_notwaiting; + return (1); + } + else if (gdb.ACKstatus == ne_gdb_ack_nacked) + { + gdb.ACKstatus = ne_gdb_ack_notwaiting; + return (0); + } + } + } +#endif +#endif + return(0); +} + +/* + * Send a packet, preceded by $, + * and followed by #checksum. + */ +void PutGDBPacket(char *aBuffer) +{ + int checksum; + char c; + char *origPtr; + int cnt=0; + + origPtr = aBuffer; // Remember in case we get a NACK + if (gdb.comlink == ne_gdb_serial) + { +startPutSerial: + GDBPutChar('$'); + checksum = 0; + while((c = *aBuffer++) != 0) + { + checksum += c; + GDBPutChar(c); + } + GDBPutChar('#'); + GDBPutChar(dHexChars[(checksum >> 4) & 15]); + GDBPutChar(dHexChars[checksum & 15]); + + if (!GDBGetACK ()) + { + aBuffer = origPtr; + if (++cnt < GDB_RETRY_CNT) goto startPutSerial; + } + } +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + else + { + if (gdb.host_ip_address != 0) + { + int i; + int result; + char c1; + + i = 0; + c = aBuffer[i]; + if (c==0) return; //there is no data in packet, so why bother sending + aBuffer[i++] = '$'; + checksum = 0; + do + { + checksum += c; + c1 = aBuffer[i]; + aBuffer[i++] = c; + c = c1; + } while (c != 0); + + aBuffer[i++] = '#'; + aBuffer[i++] = dHexChars[(checksum >> 4) & 15]; + aBuffer[i++] = dHexChars[checksum & 15]; + aBuffer[i++] = 0; +startPutEth: + result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0, + gdb.host_ip_address, + gdb.host_port_number); + + if (!GDBGetACK ()) + { + if (++cnt < GDB_RETRY_CNT) goto startPutEth; + } + aBuffer[0] = 0; //clear packet to + } + } +#endif +#endif +} + +int PutTracePacket(char *aBuffer, int size) +{ + int checksum; +#ifdef ethernet_exists + char c; +#endif + int i; + int cnt=0; + + if (gdb.comlink == ne_gdb_serial) + { +startPutSerial: + GDBPutChar('$'); + checksum = 0; + for (i=0; i> 4) & 15]); + GDBPutChar(dHexChars[checksum & 15]); + + if (!GDBGetACK ()) + { + if (++cnt < GDB_RETRY_CNT) goto startPutSerial; + } + } +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + else + { + int result; + char c1; + + checksum = 0; + c = '$'; + for (i=0; i> 4) & 15]; + aBuffer[i++] = dHexChars[checksum & 15]; + aBuffer[i++] = 0; +ethResend: + if (gdb.host_ip_address != 0) + { + result = nr_plugs_send_to (gdb.gdb_eth_plug, aBuffer, i, 0, + gdb.host_ip_address, + gdb.host_port_number); + } + if (!GDBGetACK ()) + { + if (++cnt < GDB_RETRY_CNT) goto ethResend; + } + aBuffer[0]=0; + } +#endif +#endif + if (cnt < GDB_RETRY_CNT) return 1; + else return 0; +} + +void PutGDBOKPacket(char *aBuffer) + { + aBuffer[0] = 'O'; + aBuffer[1] = 'K'; + aBuffer[2] = 0; + PutGDBPacket(aBuffer); + } + +#if nasys_debug_core + +//some defines used exclusively for TRACE data xfer +//stepsize is the ascii hex step value i.e. twice the binary length +#define stepsize (2*(2*sizeof(int) + sizeof (char))) +#define MAX_TRACE_BYTES (((int)((2*MAX_DATA_SIZE-2)/stepsize))*stepsize) + +int Trace_Read_Intercept (char *aBuffer) +{ + int cnt=0; + unsigned int data; + unsigned char code; + int byteCount; + unsigned char *w; + unsigned short dataAccumulate; + int status; + + w = aBuffer; + w++; //skip past the m + if (*w++ == 't') //see if this is a special "memory trace" packet + { + w = Hex2Value(w,&byteCount); //get the number of bytes to transfer + + //turn byteCount to a multiple of stepsize + byteCount = ((int)(byteCount/stepsize))*stepsize; + + //wait until fifo empties + nm_debug_get_reg(status, np_debug_write_status); + while (status&np_debug_write_status_writing_mask) nm_debug_get_reg(status,np_debug_write_status); + + // loop through total size + while (byteCount > 0) + { + w=aBuffer; //reset w to beginning of buffer + + //calculate the number of bytes in this packet + if (byteCount > MAX_TRACE_BYTES) dataAccumulate = MAX_TRACE_BYTES; + else dataAccumulate = byteCount; + + //insert data size at beginning of packet + w = MemToHex((char *)&dataAccumulate, w, sizeof (dataAccumulate)); + + byteCount -= dataAccumulate; //decrement byteCount + + // accumulate a full buffer + for (cnt=0; cnt MAX_DATA_SIZE) byteCount = MAX_DATA_SIZE; + + // mA,L -- request memory + w = aBuffer; + w = MemToHex((char *)startAddr,w,byteCount); + PutGDBPacket(aBuffer); + } + +void DoGDBCommand_M(char *aBuffer) + { + char *w; + int startAddr,byteCount; + + w = aBuffer; + w++; // past 'M' + w = Hex2Value(w,&startAddr); + w++; // past ',' + w = Hex2Value(w,&byteCount); + w++; // past ':' + + GDB_Print2("M from %x to %x",startAddr,byteCount); + + // MA,L:values -- write to memory + + w = HexToMem(w,(char *)startAddr,byteCount); + + // Send "OK" + PutGDBOKPacket(aBuffer); + } + +int Debug_Read_Intercept (char *aBuffer) +{ + unsigned int data; + int index; + unsigned char *w; + + w = aBuffer; + w++; //skip past the g + if (*w++ == 'g') //see if this is a special "register read" packet + { + w = Hex2Value(w,&index); //get the index of the register to be read + + nm_debug_get_reg (data, index); + + //assemble the output packet + w=aBuffer; //reset w to beginning of buffer + w = MemToHex((char *)&data, w, sizeof (data)); + *w++ = 0; + + //now send it + PutTracePacket (aBuffer,sizeof (data) * 2); + + return 1; + } + return 0; +} + +// Return the values of all the registers +void DoGDBCommand_g(NiosGDBGlobals *g) + { + char *w; + + if (Debug_Read_Intercept (g->textBuffer)) return; + + w = g->textBuffer; + + w = MemToHex((char *)(&g->registers),w,sizeof(g->registers)); + PutGDBPacket(g->textBuffer); + GDB_Print2("Sent Registers",0,0); + } + +int Debug_Write_Intercept (char *aBuffer) +{ + unsigned int data; + int index; + unsigned char *w; + + w = aBuffer; + w++; //skip past the g + if (*w++ == 'g') //see if this is a special "register read" packet + { + w = Hex2Value(w,&index); //get the index of the register to be written + w++; // past ',' + w = Hex2Value(w,&data); + + nm_debug_set_reg (data, index); + + //now send it + // Send "OK" + PutGDBOKPacket(aBuffer); + + return 1; + } + return 0; +} + +void DoGDBCommand_G(NiosGDBGlobals *g) + { + char *w; + + if (Debug_Write_Intercept (g->textBuffer)) return; + + w = g->textBuffer; + w++; // skip past 'G' + w = HexToMem(w,(char *)(&g->registers), sizeof(g->registers) ); + + // Send "OK" + PutGDBOKPacket(g->textBuffer); + + GDB_Print2("Received Registers",0,0); + } + +// Return last signal value +void DoGDBCommand_qm(NiosGDBGlobals *g) + { + char *w; + + w = g->textBuffer; + + *w++ = 'S'; + *w++ = '2'; + *w++ = '3'; // make up a signal for now... + *w++ = 0; + PutGDBPacket(g->textBuffer); + } + +void DoGDBCommand_q(NiosGDBGlobals *g) +{ +#ifdef na_ssram_detect_in + short int* ssram_exists; +#endif + char *w; + w = g->textBuffer; + + w++; /* skip past the q */ + switch (*w) { + case ('A'): + w = g->textBuffer; + + /* handle intialization information */ + /* is nios_ocd available? */ +#ifdef nasys_debug_core + *w++ = nasys_debug_core + '0'; +#else + *w++ = '0'; +#endif + *w++ = ','; + + /* determine if the SSRAM debugger board is + * physically present */ +#ifdef na_ssram_detect_in + ssram_exists = (short int*) na_ssram_detect_in; + *w++ = !(*ssram_exists) + '0'; +#else + *w++ = '0'; +#endif + *w++ = ','; + + /* print out the max size of a trace packet */ +#if nasys_debug_core + sprintf (w, "%04x", MAX_TRACE_BYTES); +#else + sprintf (w, "0000"); +#endif + + break; + case ('B'): + w = g->textBuffer; + + /* returns 1 if it was an OCD interrupt + * returns 0 if it was software breakpoint */ + if (gdb.trapNumber == nasys_debug_core_irq) { + *w++ = '1'; + } else { + *w++ = '0'; + } + + *w++ = 0; + break; + default: + w = g->textBuffer; + + *w = 0; + break; + } + + PutGDBPacket(g->textBuffer); +} + + +void GDBInsertBreakpoint(NiosGDBGlobals *g,short *address) + { + NiosGDBBreakpoint *b; + + GDB_Print2("breakpoint 0x%x",(int)address,0); + if(g->breakpointCount < kMaximumBreakpoints) + { + b = &g->breakpoint[g->breakpointCount++]; + b->address = address; + b->oldContents = *b->address; + *b->address = 0x7904; + } + } + +void GDBRemoveBreakpoints(NiosGDBGlobals *g) + { + NiosGDBBreakpoint *b; + int i; + + for(i = 0; i < g->breakpointCount; i++) + { + b = &g->breakpoint[i]; + *b->address = b->oldContents; + b->address = 0; + } + + g->breakpointCount = 0; + } + +int NiosInstructionIsTrap5(unsigned short instruction) + { + return instruction == 0x7905; + } + +int NiosInstructionIsPrefix(unsigned short instruction) + { + return (instruction >> 11) == 0x13; + } + +int NiosInstructionIsSkip(unsigned short instruction) + { + int op6; + int op11; + + op6 = (instruction >> 10); + op11 = (instruction >> 5); + + return (op6 == 0x14 // SKP0 + || op6 == 0x15 // SKP1 + || op11 == 0x3f6 // SKPRz + || op11 == 0x3f7 // SKPS + || op11 == 0x3fa); // SKPRnz + } + +int NiosInstructionIsBranch(unsigned short instruction,short *pc,short **branchTargetOut) + { + int op4; + int op7; + int op10; + short *branchTarget = 0; + int result = 0; + + op4 = (instruction >> 12); + op7 = (instruction >> 9); + op10 = (instruction >> 6); + + if(op4 == 0x08) // BR, BSR + { + int offset; + + result = 1; + offset = instruction & 0x07ff; + if(offset & 0x400) // sign extend + offset |= 0xffffF800; + branchTarget = pc + offset + 1; // short * gets x2 scaling automatically + } + else if(op10 == 0x1ff) // JMP, CALL + { + result = 1; + branchTarget = (short *)(gdb.registers.r[instruction & 31] * 2); + } + else if(op7 == 0x3d) // JMPC, CALLC + { + result = 1; + branchTarget = pc + 1 + (instruction & 0x0ffff); +#ifdef __nios32__ + branchTarget = (short *)((int)branchTarget & 0xffffFFFc); // align 32... +#else + branchTarget = (short *)((int)branchTarget & 0xFFFe); // align 16... +#endif + branchTarget = (short *)(*(int *)branchTarget); + } + + if(branchTargetOut) + *branchTargetOut = branchTarget; + + return result; + } + +// ------------------------- +// Step at address +// +// "stepping" involves inserting a +// breakpoint at some reasonable +// spot later than the current program +// counter +// +// On the Nios processor, this is +// nontrivial. For example, we should +// not break up a PFX instruction. + +void DoGDBCommand_s(NiosGDBGlobals *g) + { + char *w; + int x; + short *pc; + short *branchTarget; + unsigned short instruction; + int stepType; + + /* + * First, if there's an argument to the packet, + * set the new program-counter value + */ + + w = g->textBuffer; + w++; + if(HexCharToValue(*w) >= 0) + { + w = Hex2Value(w,&x); + g->registers.pc = x; + } + + /* + * Scan forward to see what the + * most appropriate location(s) for + * a breakpoint will be. + * + * The rules are: + * 1. If *pc == PFX, break after modified instruction. + * 2. If *pc == BR,BSR,JMP,CALL, break at destination + * 3. If *pc == SKIP, break right after SKIP AND after optional instruction, + which might, of course, be prefixed. + * 4. Anything else, just drop in the breakpoint. + */ + + pc = (short *)(int)g->registers.pc; + + instruction = *pc; + stepType = 0; + + if(NiosInstructionIsPrefix(instruction)) + { + /* + * PFX instruction: skip til after it + */ + while(NiosInstructionIsPrefix(instruction)) + { + pc++; + instruction = *pc; + } + + GDBInsertBreakpoint(g,pc + 1); + stepType = 1; + } + else if(NiosInstructionIsBranch(instruction,pc,&branchTarget)) + { + GDBInsertBreakpoint(g,branchTarget); + stepType = 2; + } + else if(NiosInstructionIsSkip(instruction)) + { + short *pc2; + stepType = 3; + + /* + * Skip gets to breaks: one after the skippable instruction, + * and the skippable instruction itself. + * + * Since Skips know how to skip over PFX's, we have to, too. + */ + pc2 = pc; // the Skip instruction + do + { + pc2++; + } while(NiosInstructionIsPrefix(*pc2)); + // pc2 now points to first non-PFX after Skip + GDBInsertBreakpoint(g,pc2+1); + GDBInsertBreakpoint(g,pc+1); + } + else + GDBInsertBreakpoint(g,pc+1); // the genericest case + + GDB_Print2("Program Steppingat 0x%x (%d)",g->registers.pc,stepType); + } + +// ----------------------------- +// Continue at address + +void DoGDBCommand_c(NiosGDBGlobals *g) + { + char *w; + int x; + w = g->textBuffer; + + w++; // past command + + // Anything in the packet? if so, + // use it to set the PC value + + if(HexCharToValue(*w) >= 0) + { + w = Hex2Value(w,&x); + g->registers.pc = x; + } + + GDB_Print2("Program Running at 0x%x",g->registers.pc,0); + } + +// ---------------------- +// Kill + +void DoGDBCommand_k(NiosGDBGlobals *g) + { + return; + } + + +/* + * If we've somehow skidded + * to a stop just after a PFX instruction + * back up the program counter by one. + * + * That way, we can't end up with an accidentally-unprefixed + * instruction. + * + * We do this just before we begin running + * again, so that when the host queries our + * registers, we report the place we actually + * stopped. + */ + +void MaybeAdjustProgramCounter(NiosGDBGlobals *g) + { + short instruction; + if(g->registers.pc) + { + instruction = *(short *)(int)(g->registers.pc - 2); + if(NiosInstructionIsPrefix(instruction)) + g->registers.pc -= 2; + else + { + // If the *current* instruction is Trap5, we must skip it! + instruction = *(short *)(int)(g->registers.pc); + if(NiosInstructionIsTrap5(instruction)) + g->registers.pc += 2; + } + } + } + +/* + * GDBMainLoop - this is the main processing loop + * for the GDB stub. + */ +void GDBMainLoop (void) +{ + while(1) + { + if (GetGDBPacket(gdb.textBuffer) > 0) + { + + GDB_Print2(gdb.textBuffer,0,0); + switch(gdb.textBuffer[0]) + { + case 's': + DoGDBCommand_s(&gdb); + goto startRunning; + break; + + case 'c': // continue + DoGDBCommand_c(&gdb); + + // if the PC is something other than 0, it's + // probably ok to exit and go there + + startRunning: + if(gdb.registers.pc) + { + MaybeAdjustProgramCounter(&gdb); + return; + } + break; + + case 'm': // memory read + DoGDBCommand_m(gdb.textBuffer); + break; + + case 'M': // memory set + DoGDBCommand_M(gdb.textBuffer); + break; + + case 'g': // registers read + DoGDBCommand_g(&gdb); + break; + + case 'G': //registers set + DoGDBCommand_G(&gdb); + break; + + case 'k': //kill process + DoGDBCommand_k(&gdb); + break; + + case '?': // last exception value + DoGDBCommand_qm(&gdb); + break; + + case 'q': + DoGDBCommand_q(&gdb); + break; + + default: // return empty packet, means "yeah yeah". + gdb.textBuffer[0] = 0; + PutGDBPacket(gdb.textBuffer); + break; + } + } + } + +} + +// ----------main------------ +void GDBMain(void) +{ + int i; + + for(i = 0; i < kTextBufferSize; i++) + gdb.textBuffer[i] = i; + + GDBRemoveBreakpoints(&gdb); + +#ifdef __KERNEL__ +/* + * Inform the user that they need to add the symbol file for the application + * that is just starting up. Display the .text .data .bss regions. + */ + if (gdb.trapNumber == 5) { + extern struct task_struct *_current_task; + sprintf(gdb.textBuffer, + "\r\n\nGDB: trap 5 at 0x%08lX", gdb.registers.pc); + puts(gdb.textBuffer); + if (_current_task) { + if ( _current_task->mm->start_code > _etext ) + sprintf(gdb.textBuffer, + "\r\nGDB: Enter the following command in the nios-elf-gdb Console Window:" + "\r\nGDB: add-symbol-file %s.abself 0x%08lX 0x%08lX 0x%08lX\r\n\n", + _current_task->comm, + (unsigned long)_current_task->mm->start_code, + (unsigned long)_current_task->mm->start_data, + (unsigned long)_current_task->mm->end_data ); + else + sprintf(gdb.textBuffer, + ", kernel process: %s\r\n", _current_task->comm ); + } else + sprintf(gdb.textBuffer, + ", kernel process unknown\r\n" ); + puts(gdb.textBuffer); + } +#endif + + // Send trapnumber for breakpoint encountered. No other signals. + + gdb.textBuffer[0] = 'S'; + gdb.textBuffer[1] = '0'; + +#if nasys_debug_core + if (gdb.trapNumber == nasys_debug_core_irq) + { + /* gdb.textBuffer[2] = '8'; */ + gdb.textBuffer[2] = '5'; + } + else + { + gdb.textBuffer[2] = '5'; + } +#else + gdb.textBuffer[2] = '5'; +#endif + gdb.textBuffer[3] = 0; + PutGDBPacket(gdb.textBuffer); + + GDB_Print2("Trap %2d At 0x%x", + gdb.trapNumber,gdb.registers.pc); +// printf ("Trap %d at 0x%x\n",gdb.trapNumber,gdb.registers.pc); +// for (i=0;i<32;i++) printf (" register[%d] = 0x%x\n",i,gdb.registers.r[i]); + + GDBMainLoop (); +} + +// +---------------------------------- +// | gdb_eth_proc -- gets called for udp packets +// | from the host bound for gdb stub +#ifdef ETHER_DEBUG +#ifdef ethernet_exists +int gdb_eth_proc(int plug_handle, + void *context, + ns_plugs_packet *p, + void *payload, + int payload_length) +{ + int i; + char *buf = (char *)payload; + // if this is a stop request, set a flag to stop after nr_plugs_idle + // leave it up to the host to prevent stops from being sent while stub is running??? + + if (*buf == 3) gdb.stop = 1; + + // if we're waiting for an ack, check that here + if (gdb.ACKstatus == ne_gdb_ack_waiting) + { + if (buf[0] == '+') + { + gdb.ACKstatus = ne_gdb_ack_acked; + return 0; + } + else if (buf[0] == '-') + { + gdb.ACKstatus = ne_gdb_ack_nacked; + return 0; + } + } + strcpy (gdb.textBuffer, buf); //all commands should be zero terminated strings + + gdb.textBuffer[payload_length] = 0; //terminate string + + gdb.host_ip_address=((ns_plugs_ip_packet *)(p[ne_plugs_ip].header))->source_ip_address; + gdb.host_port_number=((ns_plugs_udp_packet *)(p[ne_plugs_udp].header))->source_port; + + return 0; +} + +int nr_dbg_plugs_idle (void) +{ + int result; + + result = nr_plugs_idle (); + if (gdb.stop) + { + gdb.stop = 0; +//;dgt2;tmp; asm ("TRAP #5"); + } + return result; +} +#endif +#endif + + +/* + * int main(void) + * + * All we really do here is install our trap # 3, + * and call it once, so that we're living down in + * the GDBMain, trap handler. + */ + +extern int StubBreakpointHandler; +extern int StubHarmlessHandler; +#if nasys_debug_core +extern int StubHWBreakpointHandler; +#endif +#ifdef nasys_debug_uart +extern int StubUartHandler; +#endif + +void gdb_local_install(int active) +{ + unsigned int *vectorTable; + unsigned int stubBreakpointHandler; + unsigned int stubHarmlessHandler; +#if nasys_debug_core + unsigned int stubHWBreakpointHandler; +#endif + + gdb.breakpointCount = 0; + gdb.textBuffer[0] = 0; + + vectorTable = (int *)nasys_vector_table; + stubBreakpointHandler = ( (unsigned int)(&StubBreakpointHandler) ) >> 1; + stubHarmlessHandler = ( (unsigned int)(&StubHarmlessHandler) ) >> 1; +#if nasys_debug_core + stubHWBreakpointHandler = ( (unsigned int)(&StubHWBreakpointHandler) ) >> 1; +#endif + + /* + * Breakpoint & single step both go here + */ + vectorTable[na_BreakpointTrap] = stubBreakpointHandler; + vectorTable[na_SingleStepTrap] = stubBreakpointHandler; + vectorTable[na_StartGDBTrap] = active ? stubBreakpointHandler : stubHarmlessHandler; + /* + * If it exists, Hardware Breakpoint has a different entry point + */ +#if nasys_debug_core + vectorTable[na_debug_peripheral_irq] = stubHWBreakpointHandler; +#endif + +#ifndef __KERNEL__ +#ifdef nasys_debug_uart + if (gdb.comlink == ne_gdb_serial) + { + np_uart *uart = (np_uart *)nasys_debug_uart; + unsigned int stubUartHandler = ((unsigned int)(&StubUartHandler)) >> 1; + + vectorTable[nasys_debug_uart_irq] = stubUartHandler; //set Uart int vector + uart->np_uartcontrol = np_uartcontrol_irrdy_mask; //enable Rx intr + } +#endif +#endif +} + +void nios_gdb_install(int active) +{ + gdb.comlink = ne_gdb_serial; + gdb_local_install (active); +} + +#ifdef ETHER_DEBUG +#ifdef ethernet_exists +void nios_gdb_install_ethernet (int active) +{ + int result; + host_16 host_port = GDB_ETH_PORT; + + gdb.comlink = ne_gdb_ethernet; + gdb_local_install (active); + + result = nr_plugs_create (&gdb.gdb_eth_plug, ne_plugs_udp, host_port, gdb_eth_proc, 0, 0); + //if unabled to open ethernet plug, switch back to default serial interface + if (result) + { + printf ("nr_plugs_create failed %d\n",result); + gdb.comlink = ne_gdb_serial; + return; + } + result = nr_plugs_connect (gdb.gdb_eth_plug, 0, -1, -1); + if (result) + { + printf ("nr_plugs_connect fialed %d\n",result); + gdb.comlink = ne_gdb_serial; + return; + } +} +#endif +#endif + +#ifdef nios_gdb_breakpoint + #undef nios_gdb_breakpoint +#endif + +void nios_gdb_breakpoint(void) + { + /* + * If you arrived here, you didn't include + * the file "nios_peripherals.h", which + * defines nios_gdb_breakpoint as a + * macro that expands to TRAP 5. + * + * (No problem, you can step out + * of this routine.) + */ +//;dgt2;tmp; asm("TRAP 5"); + } + +// end of file diff --git a/arch/nios2nommu/kernel/nios_gdb_stub.h b/arch/nios2nommu/kernel/nios_gdb_stub.h new file mode 100644 index 00000000..3900109f --- /dev/null +++ b/arch/nios2nommu/kernel/nios_gdb_stub.h @@ -0,0 +1,105 @@ +// file: nios_gdb_stub.h +// Author: Altera Santa Cruz \ 2000 +// +// You can modify this header file to +// enable some features useful for +// debugging the debugger. They're +// good features also to just show +// signs of life on your Nios board. +// But they consume valuable peripherals! +// +// The 'GDB_DEBUG_PRINT' option ties +// up the LCD living on the 5v port, +// showing useful internals of the stub. +// +// dvb@altera.com +// + +#ifdef ETHER_DEBUG +#ifdef na_enet +#define ethernet_exists +#endif +#endif + +#ifdef ETHER_DEBUG +#ifdef ethernet_exists +#include "plugs.h" +#endif +#endif + +#define MAX_DATA_SIZE 650 +#define kTextBufferSize ((2*MAX_DATA_SIZE)+4) +#define kMaximumBreakpoints 4 +#define GDB_ETH_PORT 7070 +#define GDB_WHOLE_PACKET 0 +#define GDB_SKIP_FIRST 1 +#define GDB_RETRY_CNT 3 + +/* + * This register structure must match + * its counterpart in the GDB host, since + * it is blasted across in byte notation. + */ +typedef struct + { + int r[32]; + long pc; + short ctl0; + short ctl1; + short ctl2; + short ctl3; + } NiosGDBRegisters; + +typedef struct + { + short *address; + short oldContents; + } NiosGDBBreakpoint; + +typedef struct + { + NiosGDBRegisters registers; + int trapNumber; // stashed by ISR, to distinguish types + char textBuffer[kTextBufferSize]; + int breakpointCount; // breakpoints used for stepping + int comlink; + int stop; + int gdb_eth_plug; + NiosGDBBreakpoint breakpoint[kMaximumBreakpoints]; +#ifdef ETHER_DEBUG +#ifdef ethernet_exists + volatile int ACKstatus; + net_32 host_ip_address; + net_16 host_port_number; +#endif +#endif + } NiosGDBGlobals; + +#ifdef ETHER_DEBUG +#ifdef ethernet_exists +enum +{ + ne_gdb_ack_notwaiting, + ne_gdb_ack_waiting, + ne_gdb_ack_acked, + ne_gdb_ack_nacked +}; +#endif +#endif + +enum +{ + ne_gdb_serial, + ne_gdb_ethernet +}; + +#ifndef GDB_DEBUG_PRINT + #define GDB_DEBUG_PRINT 0 +#endif + +void GDB_Main(void); // initialize gdb and begin. + +char GDBGetChar(void); +void GDBPutChar(char c); +void GDB_Print2(char *s,int v1,int v2); + diff --git a/arch/nios2nommu/kernel/nios_gdb_stub_io.c b/arch/nios2nommu/kernel/nios_gdb_stub_io.c new file mode 100644 index 00000000..e0d8f82a --- /dev/null +++ b/arch/nios2nommu/kernel/nios_gdb_stub_io.c @@ -0,0 +1,39 @@ +// Modified for uClinux - Vic - Apr 2002 +// From: + +// file: nios_gdb_stub_IO.c +// +// Single character I/O for Nios GDB Stub + +#ifndef __KERNEL__ +#include "nios.h" +#else +#include +#endif + +#include "nios_gdb_stub.h" + +#ifdef nasys_debug_uart + #define GDB_UART nasys_debug_uart +#endif + +char GDBGetChar(void) +{ + char c = 0; + +#ifdef GDB_UART + while( (c = (char)nr_uart_rxchar(GDB_UART)) < 0 ) + ; +#endif + + return c; +} + +void GDBPutChar(char c) +{ +#ifdef GDB_UART + nr_uart_txchar(c, GDB_UART); +#endif +} + +// End of file diff --git a/arch/nios2nommu/kernel/nios_gdb_stub_isr.S b/arch/nios2nommu/kernel/nios_gdb_stub_isr.S new file mode 100644 index 00000000..c4af09a4 --- /dev/null +++ b/arch/nios2nommu/kernel/nios_gdb_stub_isr.S @@ -0,0 +1,99 @@ +/*-------------------------------------------------------------------- + * + * Assembly language portions of Nios GDB Stub + * + * arch\nios2nommu\kernel\switch.S + * + * Derived from Nios1 + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Modified for uClinux - Vic - Apr 2002 + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +//;dgt2;tmp; + + .equ ethernet_exists, 1 + + + .equ gdbRegistersGeneral,0 + .equ gdbRegistersPC,32 + .equ gdbRegistersCtl0Ctl1,33 + .equ gdbRegistersCtl2Ctl3,34 + .equ gdbTrapNumber,35 ; ISR can report trap number here + + + .text + + .global StubBreakpointHandler + .global StubHarmlessHandler + .global StubButtonHandler + .global StubHWBreakpointHandler + .global GDBMain + + .comm _gdb_stub_stack,1024,4 ; Local stack, statically allocated. + .equ gdbStubStacktop,_gdb_stub_stack+992 + + +StubHarmlessHandler: +//;dgt2;tmp + + .equ gdbBreakChar,0x3 + .global StubUartHandler + +StubUartHandler: +//;dgt2;tmp + +StubUartRx: +//;dgt2;tmp + +StubHWBreakpointHandler: +//;dgt2;tmp + +StubBreakpointHandler: +//;dgt2;tmp + +#ifdef __KERNEL__ +;---------------------------------------- +; Name: nr_uart_rxchar +; Description: Read character if available +; Input: %o0: UART base to use +; Output: %o0 = character 0-0xff, or -1 if none present +; Side Effects: %g0 & %g1 altered +; CWP Depth: 0 +; + + .global nr_uart_rxchar +nr_uart_rxchar: +//;dgt2;tmp + + +;---------------------------------------- +; Name: nr_uart_txchar +; Description: Send a single byte out the UART +; Input: %o0 = A character +; %o1 = the UART to use, 0 for default +; Output: none +; Side Effects: %g0 & %g1 altered, CPU waits for UART +; CWP Depth: 0 +; + +; nr_uart_txchar + .global nr_uart_txchar +nr_uart_txchar: +//;dgt2;tmp + +#endif diff --git a/arch/nios2nommu/kernel/pio.c b/arch/nios2nommu/kernel/pio.c new file mode 100644 index 00000000..013a64b9 --- /dev/null +++ b/arch/nios2nommu/kernel/pio.c @@ -0,0 +1,154 @@ +/* + * linux/arch/nios2nommu/kernel/pio.c + * "Example" drivers(LEDs and 7 seg displays) of the PIO interface + * on Nios Development Kit. + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Written by Wentao Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Microtronix Datacom Ltd."); +MODULE_DESCRIPTION("Drivers of PIO devices (LEDs and 7 seg) on Nios kit"); +MODULE_LICENSE("GPL"); + +#undef CONFIG_PIO_SEG +#ifdef na_seven_seg_pio +#define CONFIG_PIO_SEG +#define PIO_SEG_IO na_seven_seg_pio +#endif + +#undef CONFIG_PIO_LED +#ifdef na_led_pio +#define CONFIG_PIO_LED +#define PIO_LED_IO na_led_pio +#endif + +#define PDEBUG printk + +/* routines for 7-segment hex display */ +#ifdef CONFIG_PIO_SEG +static unsigned char _hex_digits_data[] = { + 0x01, 0x4f, 0x12, 0x06, 0x4c, /* 0-4 */ + 0x24, 0x20, 0x0f, 0x00, 0x04, /* 5-9 */ + 0x08, 0x60, 0x72, 0x42, 0x30, /* a-e */ + 0x38 /* f */ +}; + +void pio_seg_write(int value) +{ + int led_value; + + /* Left Hand Digit, goes to PIO bits 8-14 */ + led_value = _hex_digits_data[value & 0xF]; + led_value |= (_hex_digits_data[(value >> 4) & 0xF]) << 8; + + outl(led_value, &(PIO_SEG_IO->np_piodata)); +} + +static void __init pio_seg_init(void) +{ + pio_seg_write(0); +} +#endif + + +/* routines for LED display */ +#ifdef CONFIG_PIO_LED +void pio_led_write(int value) +{ + np_pio *pio=(np_pio *)(PIO_LED_IO); + + //outl(-1, &pio->np_piodirection); + outl(value, &pio->np_piodata); +} + +static void __init pio_led_init(void) +{ + np_pio *pio=(np_pio *)(PIO_LED_IO); + + outl(-1, &pio->np_piodirection); + outl(0x0, &pio->np_piodata); +} +#endif + +/* timing routines */ +#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) +static struct timer_list display_timer; +static int restart_timer=1; +static int timer_counter=0; +static void display_timeout(unsigned long unused) +{ +#ifdef CONFIG_PIO_SEG + pio_seg_write(++timer_counter); +#endif + +#ifdef CONFIG_PIO_LED + pio_led_write(timer_counter); +#endif + if (restart_timer) { + display_timer.expires = jiffies + HZ; /* one second */ + add_timer(&display_timer); + } +} +#endif + +int __init pio_init(void) +{ +#ifdef CONFIG_PIO_SEG + request_mem_region((unsigned long)PIO_SEG_IO, sizeof(np_pio), "pio_7seg"); + pio_seg_init(); +#endif + +#ifdef CONFIG_PIO_LED + request_mem_region((unsigned long)PIO_LED_IO, sizeof(np_pio), "pio_led"); + pio_led_init(); +#endif + +#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) + /* init timer */ + init_timer(&display_timer); + display_timer.function = display_timeout; + display_timer.data = 0; + display_timer.expires = jiffies + HZ * 10; /* 10 seconds */ + add_timer(&display_timer); +#endif + + return 0; +} + +static void __exit pio_exit(void) +{ +#ifdef CONFIG_PIO_SEG + pio_seg_write(0); + release_mem_region((unsigned long)PIO_SEG_IO, sizeof(np_pio)); +#endif + +#ifdef CONFIG_PIO_LED + pio_led_write(0); + release_mem_region((unsigned long)PIO_LED_IO, sizeof(np_pio)); +#endif + +#if defined(CONFIG_PIO_SEG) || defined(CONFIG_PIO_LED) + restart_timer=0; + del_timer_sync(&display_timer); +#endif +} +module_init(pio_init); +module_exit(pio_exit); + diff --git a/arch/nios2nommu/kernel/process.c b/arch/nios2nommu/kernel/process.c new file mode 100644 index 00000000..75610524 --- /dev/null +++ b/arch/nios2nommu/kernel/process.c @@ -0,0 +1,577 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/process.c + * + * Derived from M68knommu + * + * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2000-2002, David McCullough + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * 68060 fixes by Jesper Skov + * Jan/20/2004 dgt NiosII + * rdusp() === (pt_regs *) regs->sp + * Monday: + * asm-nios2nommu\processor.h now bears + * inline thread_saved_pc + * (struct thread_struct *t) + * Friday: it's back here now + * + ---------------------------------------------------------------------*/ + + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +//;dgt2;#include +#include +#include +#include + +asmlinkage void ret_from_fork(void); + +/* + * The following aren't currently used. + */ +void (*pm_idle)(void) = NULL; +EXPORT_SYMBOL(pm_idle); + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); + +void default_idle(void) +{ + local_irq_disable(); + if (!need_resched()) { + local_irq_enable(); + __asm__("nop"); // was asm sleep + } else + local_irq_enable(); +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + while (1) { + while (!need_resched()) + idle(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +/* + * The development boards have no way to pull a board + * reset. Just jump to the cpu reset address and let + * the code in head.S take care of disabling peripherals. + */ + +void machine_restart(char * __unused) +{ + local_irq_disable(); + __asm__ __volatile__ ( + "jmp %0\n\t" + : + : "r" (CPU_RESET_ADDRESS) + : "r4"); +} + +EXPORT_SYMBOL(machine_restart); + +void machine_halt(void) +{ + local_irq_disable(); + for (;;); +} + +EXPORT_SYMBOL(machine_halt); + +void exit_thread(void) +{ +} + +void release_thread(struct task_struct *dead_task) +{ + /* nothing to do ... */ +} + +/* + * There is no way to power off the development + * boards. So just spin lock for now. If you have + * your own board with power down circuits add you + * specific code here. + */ + +void machine_power_off(void) +{ + local_irq_disable(); + for (;;); +} + +EXPORT_SYMBOL(machine_power_off); + +void show_regs(struct pt_regs * regs) +{ + printk(KERN_NOTICE "\n"); + + printk(KERN_NOTICE "r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n", + regs->r1, regs->r2, regs->r3, regs->r4); + + printk(KERN_NOTICE "r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n", + regs->r5, regs->r6, regs->r7, regs->r8); + + printk(KERN_NOTICE "r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n", + regs->r9, regs->r10, regs->r11, regs->r12); + + printk(KERN_NOTICE "r13: %08lx r14: %08lx r15: %08lx\n", + regs->r13, regs->r14, regs->r15); + + printk(KERN_NOTICE "ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n", + regs->ra, regs->fp, regs->sp, regs->gp); + + printk(KERN_NOTICE "ea: %08lx estatus: %08lx statusx: %08lx\n", + regs->ea, regs->estatus, regs->status_extension); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + long clone_arg = flags | CLONE_VM; + mm_segment_t fs; + + fs = get_fs(); + set_fs(KERNEL_DS); + + __asm__ __volatile( + + " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */ + " movi r3, %1\n\t" /* __NR_clone */ + " mov r4, %5\n\t" /* (clone_arg */ + /* (flags | CLONE_VM)) */ + " movia r5, -1\n\t" /* usp: -1 */ + " trap\n\t" /* sys_clone */ + "\n\t" + " cmpeq r4, r3, zero\n\t"/*2nd return valu in r3 */ + " bne r4, zero, 1f\n\t"/* 0: parent, just return. */ + /* See copy_thread, called */ + /* by do_fork, called by */ + /* nios2_clone, called by */ + /* sys_clone, called by */ + /* syscall trap handler. */ + + " mov r4, %4\n\t" /* fn's parameter (arg) */ + "\n\t" + "\n\t" + " callr %3\n\t" /* Call function (fn) */ + "\n\t" + " mov r4, r2\n\t" /* fn's rtn code//;dgt2;tmp;*/ + " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */ + " movi r3, %2\n\t" /* __NR_exit */ + " trap\n\t" /* sys_exit() */ + + /* Not reached by child. */ + "1:\n\t" + " mov %0, r2\n\t" /* error rtn code (retval) */ + + : "=r" (retval) /* %0 */ + + : "i" (__NR_clone) /* %1 */ + , "i" (__NR_exit) /* %2 */ + , "r" (fn) /* %3 */ + , "r" (arg) /* %4 */ + , "r" (clone_arg) /* %5 (flags | CLONE_VM) */ + , "i" (TRAP_ID_SYSCALL) /* %6 */ + + : "r2" /* Clobbered */ + , "r3" /* Clobbered */ + , "r4" /* Clobbered */ + , "r5" /* Clobbered */ + , "ra" /* Clobbered //;mex1 */ + ); + + set_fs(fs); + return retval; +} + +void flush_thread(void) +{ + /* Now, this task is no longer a kernel thread. */ + current->thread.flags &= ~NIOS2_FLAG_KTHREAD; + +#ifdef CONFIG_FPU + unsigned long zero = 0; +#endif + set_fs(USER_DS); +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) +...;dgt2; + asm volatile (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (&zero)); +#endif +} + +/* + * "nios2_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int nios2_fork(struct pt_regs *regs) +{ + /* fork almost works, enough to trick you into looking elsewhere :-( */ + return(-EINVAL); +} + +/* + * nios2_execve() executes a new program. + */ +asmlinkage int nios2_execve(struct pt_regs *regs) +{ + int error; + char * filename; + + lock_kernel(); + filename = getname((char *) regs->r4); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, + (char **) regs->r5, + (char **) regs->r6, + regs); + putname(filename); +out: + unlock_kernel(); + return error; +} + +asmlinkage int nios2_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); +} + +asmlinkage int nios2_clone(struct pt_regs *regs) +{ + /* r4: clone_flags, r5: child_stack (usp) */ + + unsigned long clone_flags; + unsigned long newsp; + + clone_flags = regs->r4; + newsp = regs->r5; + if (!newsp) + newsp = regs->sp; + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); +} + +int copy_thread(int nr, unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long stack_offset, *retp; + + stack_offset = THREAD_SIZE - sizeof(struct pt_regs); + childregs = (struct pt_regs *) ((unsigned long) p->thread_info + stack_offset); + p->thread.kregs = childregs; + + *childregs = *regs; + childregs->r2 = 0; //;dgt2;...redundant?...see "rtnvals" below + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->ra = (unsigned long)ret_from_fork; + + if (usp == -1) + p->thread.kregs->sp = (unsigned long) childstack; + else + p->thread.kregs->sp = usp; + + p->thread.ksp = (unsigned long)childstack; + +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ +...;dgt2; + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (p->thread.fpstate[0]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } +#endif + + /* Set the return value for the child. */ + childregs->r2 = 0; //;dgt2;...redundant?...see childregs->r2 above + childregs->r3 = 1; //;dgt2;...eg: kernel_thread parent test + + /* Set the return value for the parent. */ + regs->r2 = p->pid; // Return child pid to parent + regs->r3 = 0; //;dgt2;...eg: kernel_thread parent test + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ +#ifdef CONFIG_FPU + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ +...;dgt2;tmp; + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!fpustate[0]) + return 0; + + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + :: "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + :: "m" (fpu->fpregs[0]) + : "memory"); +#endif + return 1; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + struct switch_stack *sw; + + /* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); + sw = ((struct switch_stack *)regs) - 1; + dump->regs.r1 = regs->r1; + dump->regs.r2 = regs->r2; + dump->regs.r3 = regs->r3; + dump->regs.r4 = regs->r4; + dump->regs.r5 = regs->r5; + dump->regs.r6 = regs->r6; + dump->regs.r7 = regs->r7; + dump->regs.r8 = regs->r8; + dump->regs.r9 = regs->r9; + dump->regs.r10 = regs->r10; + dump->regs.r11 = regs->r11; + dump->regs.r12 = regs->r12; + dump->regs.r13 = regs->r13; + dump->regs.r14 = regs->r14; + dump->regs.r15 = regs->r15; + dump->regs.r16 = sw->r16; + dump->regs.r17 = sw->r17; + dump->regs.r18 = sw->r18; + dump->regs.r19 = sw->r19; + dump->regs.r20 = sw->r20; + dump->regs.r21 = sw->r21; + dump->regs.r22 = sw->r22; + dump->regs.r23 = sw->r23; + dump->regs.ra = sw->ra; + dump->regs.fp = sw->fp; + dump->regs.gp = sw->gp; + dump->regs.sp = regs->sp; + dump->regs.orig_r2 = regs->orig_r2; + dump->regs.estatus = regs->estatus; + dump->regs.ea = regs->ea; + /* dump floating point stuff */ + // dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); +} + +/* + * Generic dumping code. Used for panic and debug. + */ +void dump(struct pt_regs *fp) +{ + unsigned long *sp; + unsigned char *tp; + int i; + + printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); + printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); + + if (current->mm) { + printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", + (int) current->mm->start_code, + (int) current->mm->end_code, + (int) current->mm->start_data, + (int) current->mm->end_data, + (int) current->mm->end_data, + (int) current->mm->brk); + printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", + (int) current->mm->start_stack, + (int)(((unsigned long) current) + THREAD_SIZE)); + } + + printk(KERN_EMERG "PC: %08lx\n", fp->ea); + printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->estatus, (long) fp); + printk(KERN_EMERG "r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + printk(KERN_EMERG "r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + fp->r8, fp->r9, fp->r10, fp->r11); + printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) fp->sp, + (unsigned int) fp); + + printk(KERN_EMERG "\nCODE:"); + tp = ((unsigned char *) fp->ea) - 0x20; + for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n"); + + printk(KERN_EMERG "\nKERNEL STACK:"); + tp = ((unsigned char *) fp) - 0x40; + for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n"); + printk(KERN_EMERG "\n"); + + printk(KERN_EMERG "\nUSER STACK:"); + tp = (unsigned char *) (fp->sp - 0x10); + for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n\n"); +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = ((struct switch_stack *)p->thread.ksp)->fp; //;dgt2 + do { + if (fp < stack_page+sizeof(struct task_struct) || + fp >= 8184+stack_page) //;dgt2;tmp + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); //;dgt2;tmp + return 0; +} + +/* Return saved PC of a blocked thread. */ +unsigned long thread_saved_pc(struct task_struct *t) +{ + return (t->thread.kregs->ea); +} + +/* + * Do necessary setup to start up a newly executed thread. + * Will statup in user mode (status_extension = 0). + */ +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +{ + memset((void *) regs, 0, sizeof(struct pt_regs)); + regs->estatus = NIOS2_STATUS_PIE_MSK; // No user mode setting, at least not for now + regs->ea = pc; + regs->sp = sp; + + /* check if debug flag is set */ + if (current->thread.flags & NIOS2_FLAG_DEBUG ) { + if ( *(u32*)pc == NIOS2_OP_NOP ) { + *(u32*)pc = NIOS2_OP_BREAK; + flush_icache_range(pc, pc+4); + } + } +} diff --git a/arch/nios2nommu/kernel/ptrace.c b/arch/nios2nommu/kernel/ptrace.c new file mode 100644 index 00000000..e6ff3b3b --- /dev/null +++ b/arch/nios2nommu/kernel/ptrace.c @@ -0,0 +1,352 @@ +/* + * linux/arch/m68knommu/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x00000000 + +/* Find the stack offset for a register, relative to thread.ksp. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static int regoff[] = { + -1, PT_REG(r1), PT_REG(r2), PT_REG(r3), PT_REG(r4), + PT_REG(r5), PT_REG(r6), PT_REG(r7), PT_REG(r8), + PT_REG(r9), PT_REG(r10), PT_REG(r11), PT_REG(r12), + PT_REG(r13), PT_REG(r14), PT_REG(r15), SW_REG(r16), + SW_REG(r17), SW_REG(r18), SW_REG(r19), SW_REG(r20), + SW_REG(r21), SW_REG(r22), SW_REG(r23), -1, -1, + PT_REG(gp), PT_REG(sp), -1, -1, PT_REG(ra), -1, + PT_REG(estatus), -1, -1, -1 +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PTR_R0) + return 0; + else if (regno == PTR_BA) + return 0; + else if (regno == PTR_STATUS) + return 0; + else if (regno == PTR_IENABLE) + return 0; + else if (regno == PTR_IPENDING) + return 0; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *)(task->thread.kregs + regoff[regno]); + else + return 0; + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PTR_R0) + return -1; + else if (regno == PTR_BA) + return -1; + else if (regno == PTR_STATUS) + return -1; + else if (regno == PTR_IENABLE) + return -1; + else if (regno == PTR_IPENDING) + return -1; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *) (task->thread.kregs + regoff[regno]); + else + return -1; + *addr = data; + return 0; +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Nothing special to do here, no processor debug support. + */ +void ptrace_disable(struct task_struct *child) +{ +} + +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + int ret; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + tmp = 0; /* Default return condition */ + addr = addr >> 2; /* temporary hack. */ + ret = -EIO; + if (addr < 19) { + tmp = get_reg(child, addr); +#if 0 // No FPU stuff + } else if (addr >= 21 && addr < 49) { + tmp = child->thread.fp[addr - 21]; +#ifdef CONFIG_M68KFPU_EMU + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#endif +#endif + } else if (addr == 49) { + tmp = child->mm->start_code; + } else if (addr == 50) { + tmp = child->mm->start_data; + } else if (addr == 51) { + tmp = child->mm->end_code; + } else + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + addr = addr >> 2; /* temporary hack. */ + + if (addr == PTR_ESTATUS) { + data &= SR_MASK; + data |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK); + } + if (addr < 19) { + if (put_reg(child, addr, data)) + break; + ret = 0; + break; + } +#if 0 // No FPU stuff + if (addr >= 21 && addr < 48) + { +#ifdef CONFIG_M68KFPU_EMU + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } +#endif + child->thread.fp[addr - 21] = data; + ret = 0; + } +#endif + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + } + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + + ret = 0; + if (child->state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + } + + /* + * Single stepping requires placing break instructions in + * the code to break back. If you are stepping through a + * conditional branch you need to decode the test and put + * the break in the correct location. + */ + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + if (i == PTR_ESTATUS) { + tmp &= SR_MASK; + tmp |= get_reg(child, PTR_ESTATUS) & ~(SR_MASK); + } + put_reg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + +#ifdef PTRACE_GETFPREGS + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = 0; + if (copy_to_user((void *)data, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + +#ifdef PTRACE_SETFPREGS + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->thread.fp, (void *)data, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + + default: + ret = -EIO; + break; + } + return ret; +} + +asmlinkage void syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/arch/nios2nommu/kernel/semaphore.c b/arch/nios2nommu/kernel/semaphore.c new file mode 100644 index 00000000..0c7d11bb --- /dev/null +++ b/arch/nios2nommu/kernel/semaphore.c @@ -0,0 +1,155 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/semaphore.c + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include +#include + +#ifndef CONFIG_RMW_INSNS +spinlock_t semaphore_wake_lock; +#endif + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +asmlinkage void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + + +#define DOWN_HEAD(task_state) \ + \ + \ + current->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + current->state = (task_state); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __sched __down(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __sched __down_interruptible(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, current); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/arch/nios2nommu/kernel/setup.c b/arch/nios2nommu/kernel/setup.c new file mode 100644 index 00000000..476cf2f7 --- /dev/null +++ b/arch/nios2nommu/kernel/setup.c @@ -0,0 +1,664 @@ +/* + 21Mar2001 1.1 dgt/microtronix: Altera Excalibur/Nios32 port + 30Jun2003 kenw/microtronix: Remove cmdline check in flash +*/ + +/* + * linux/arch/niosnommu/kernel/setup.c + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 2001 Vic Phillips {vic@microtronix.com} + * Copyleft (C) 2000 James D. Schettine {james@telos-systems.com} + * Copyright (C) 1999 Greg Ungerer (gerg@moreton.com.au) + * Copyright (C) 1998,2000 D. Jeff Dionne + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1995 Hamish Macdonald + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * This file handles the architecture-dependent parts of system setup + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include +#include + +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#ifdef CONFIG_NIOS_SPI +#include +extern ssize_t spi_write(struct file *filp, const char *buf, size_t count, loff_t *ppos); +extern ssize_t spi_read (struct file *filp, char *buf, size_t count, loff_t *ppos); +extern loff_t spi_lseek (struct file *filp, loff_t offset, int origin); +extern int spi_open (struct inode *inode, struct file *filp); +extern int spi_release (struct inode *inode, struct file *filp); +#endif + +#ifdef CONFIG_CONSOLE +extern struct consw *conswitchp; +#endif + +unsigned long rom_length; +unsigned long memory_start; +unsigned long memory_end; + +EXPORT_SYMBOL(memory_start); +EXPORT_SYMBOL(memory_end); + +#ifndef CONFIG_CMDLINE +#define CONFIG_CMDLINE "CONSOLE=/dev/ttyS0 root=/dev/rom0 ro" +#endif + +#ifndef CONFIG_PASS_CMDLINE +static char default_command_line[] = CONFIG_CMDLINE; +#endif +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + + +/* r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11*/ +/* r12 r13 r14 r15 or2 ra fp sp gp es ste ea*/ +static struct pt_regs fake_regs = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, (unsigned long)cpu_idle, 0, 0, 0, 0, 0, 0}; + +#define CPU "NIOS2" + +#if defined (CONFIG_CS89x0) || defined (CONFIG_SMC91111) || defined (CONFIG_OPEN_ETH) || defined (CONFIG_MTIP1000_ETH) || defined (CONFIG_DM9000_ETH) || defined (CONFIG_SMC91X) || defined (CONFIG_DM9000) || defined (CONFIG_DM9KS) + #if defined (CONFIG_MTIP1000_ETH) //;dgt3; + #include <../drivers/net/mtip1000.h> //;dgt3; + #endif //;dgt3; + + unsigned char *excalibur_enet_hwaddr; + unsigned char excalibur_enet_hwaddr_array[6]; +#endif + +// save args passed from u-boot, called from head.S +void nios2_boot_init(unsigned r4,unsigned r5,unsigned r6,unsigned r7) +{ +#if defined(CONFIG_PASS_CMDLINE) + if (r4 == 0x534f494e) // r4 is magic NIOS, to become board info check in the future + { +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r5) { + initrd_start = r5; + initrd_end = r6; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + if (r7) + strncpy(command_line, (char *)r7, COMMAND_LINE_SIZE); + } +#endif +} + +inline void flash_command(int base, int offset, short data) +{ + volatile unsigned short * ptr=(unsigned short*) (base); + + ptr[0x555]=0xaa; + ptr[0x2aa]=0x55; + ptr[offset]=data; +} + +inline void exit_se_flash(int base) +{ + flash_command(base, 0x555, 0x90); + *(unsigned short*)base=0; +} + +void setup_arch(char **cmdline_p) +{ + int bootmap_size; + extern int _stext, _etext; + extern int _edata, _end; + extern int _ramend; +#ifdef DEBUG + extern int _sdata, _sbss, _ebss; +#ifdef CONFIG_BLK_DEV_BLKMEM + extern int *romarray; +#endif +#endif +#if 0 // krh + unsigned char *psrc=(unsigned char *)((NIOS_FLASH_START + NIOS_FLASH_END)>>1); + int i=0; +#endif // krh + + memory_start = (unsigned long)&_end; + memory_end = (unsigned long) &_ramend; + +#if 0 //;kenw; + /* copy the command line from booting paramter region */ + #if defined (nasys_am29lv065d_flash_0) //;dgt; + { //;dgt; + // ...TBA... //;dgt; + } //;dgt; + #else //;dgt; + flash_command((int)psrc, 0x555, 0x88); + while ((*psrc!=0xFF) && (i>1) ); + if (command_line[0]==0) + #endif //;dgt; +#endif //;kenw; +#ifndef CONFIG_PASS_CMDLINE + memcpy(command_line, default_command_line, sizeof(default_command_line)); +#endif + + printk("\x0F\r\n\nuClinux/Nios II\n"); + printk("Altera Nios II support (C) 2004 Microtronix Datacom Ltd.\n"); + +#ifdef DEBUG + printk("KERNEL -> TEXT=0x%08x-0x%08x DATA=0x%08x-0x%08x " + "BSS=0x%08x-0x%08x\n", (int) &_stext, (int) &_etext, + (int) &_sdata, (int) &_edata, + (int) &_sbss, (int) &_ebss); + printk("KERNEL -> MEM=0x%06x-0x%06x STACK=0x%06x-0x%06x\n", + (int) memory_start, (int) memory_end, + (int) memory_end, (int) nasys_program_mem_end); +#endif + + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) 0; + init_task.thread.kregs = &fake_regs; + +#if 0 + ROOT_DEV = MKDEV(BLKMEM_MAJOR,0); +#endif + + /* Keep a copy of command line */ + *cmdline_p = &command_line[0]; + + memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = 0; + +#ifdef DEBUG + if (strlen(*cmdline_p)) + printk("Command line: '%s'\n", *cmdline_p); + else + printk("No Command line passed\n"); +#endif + + +#if defined (CONFIG_CS89x0) || defined (CONFIG_SMC91111) || defined (CONFIG_OPEN_ETH) || defined (CONFIG_MTIP1000_ETH) || defined (CONFIG_DM9000_ETH) || defined (CONFIG_SMC91X) || defined (CONFIG_DM9000) || defined (CONFIG_DM9KS) + + #if defined (CONFIG_MTIP1000_ETH) //;dgt3; + (*((np_mtip_mac *) //;dgt3; + (na_mtip_mac_control_port))). //;dgt3; + COMMAND_CONFIG = 0; //;dgt3; + #endif //;dgt3; + + /* now read the hwaddr of the ethernet --wentao*/ + + #if 1 //;dgt2; +// #if defined (nasys_am29lv065d_flash_0) //;dgt; + { //;dgt; + unsigned char *flashptr = //;dgt; + ((unsigned char *) //;dgt; + (( //;dgt; + #if defined (na_flash_kernel_end) //;dgt2; + na_flash_kernel_end //;dgt2; + #else //;dgt2; + #if defined (na_flash_kernel_base) //;dgt2; + na_flash_kernel_base + //;dgt; + #else //;dgt2; + na_flash_kernel + //;dgt2; + #endif //;dgt2; + na_flash_kernel_size //;dgt2; + #endif //;dgt2; + - 0x00010000))); //;dgt; + // last 64K of Altera stratix/cyclone flash //;dgt; + //;dgt; + if((*((unsigned long *) flashptr)) == 0x00005AFE) //;dgt; + { //;dgt; + memcpy(excalibur_enet_hwaddr_array, //;dgt; + ((void*) (flashptr+4)),6); //;dgt; + } //;dgt; + else //;dgt; + { //;dgt; + printk("\nsetup_arch: No persistant network" //;dgt; + " settings signature at %08lX\n", //;dgt; + ((unsigned long) flashptr)); //;dgt; + *((unsigned long *) //;dgt; + (&(excalibur_enet_hwaddr_array[0]))) = //;dgt; + 0x00ED0700; //;dgt2; + /* 0x00-07-ED: Altera Corporation. //;dgt; */ + *((unsigned short *) //;dgt; + (&(excalibur_enet_hwaddr_array[4]))) = //;dgt; + 0x0000; //;dgt; + /* Should be: 0x-00-07-ED-0A-03-(Random# 0-256) //;dgt2; */ + /* 0x-00-07-ED-0A-xx-yy Vermont boards //;dgt2; */ + /* 0x-00-07-ED-0B-xx-yy Rhode Island boards //;dgt2; */ + /* 0x-00-07-ED-0C-xx-yy Delaware boards //;dgt2; */ + /* 00 Internal Altera //;dgt2; */ + /* 01 Beta, pre-production//;dgt2; */ + /* 02 Beta, pre-production//;dgt2; */ + /* 03 Customer use //;dgt2; */ + } //;dgt; + } //;dgt; + #else //;dgt; + flash_command(NIOS_FLASH_START, 0x555, 0x88); + memcpy(excalibur_enet_hwaddr_array,(void*)NIOS_FLASH_START,6); + exit_se_flash(NIOS_FLASH_START);; + #endif //;dgt; + + /* now do the checking, make sure we got a valid addr */ + if (excalibur_enet_hwaddr_array[0] & (unsigned char)1) + { + printk("Ethernet hardware address:Clearing invalid bit #0\n"); + excalibur_enet_hwaddr_array[0] ^= (unsigned char)1; + } + excalibur_enet_hwaddr=excalibur_enet_hwaddr_array; +#ifdef DEBUG + printk("Setup the hardware addr for ethernet\n\t %02x %02x %02x %02x %02x %02x\n", + excalibur_enet_hwaddr[0],excalibur_enet_hwaddr[1], + excalibur_enet_hwaddr[2],excalibur_enet_hwaddr[3], + excalibur_enet_hwaddr[4],excalibur_enet_hwaddr[5]); +#endif +#endif + + + /* + * give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory + */ + bootmap_size = init_bootmem_node( + NODE_DATA(0), + memory_start >> PAGE_SHIFT, /* map goes here */ + PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ + memory_end >> PAGE_SHIFT); + /* + * free the usable memory, we have to make sure we do not free + * the bootmem bitmap so we then reserve it after freeing it :-) + */ + free_bootmem(memory_start, memory_end - memory_start); + reserve_bootmem(memory_start, bootmap_size); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) reserve_bootmem(virt_to_phys((void *)initrd_start), initrd_end - initrd_start); +#endif /* CONFIG_BLK_DEV_INITRD */ + /* + * get kmalloc into gear + */ + paging_init(); +#ifdef CONFIG_VT +#if defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif + +#ifdef DEBUG + printk("Done setup_arch\n"); +#endif + +} + +int get_cpuinfo(char * buffer) +{ + char *cpu, *mmu, *fpu; + u_long clockfreq; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + + clockfreq = nasys_clock_freq; + + return(sprintf(buffer, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clocking:\t%lu.%1luMHz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpu, mmu, fpu, + clockfreq/1000000,(clockfreq/100000)%10, + (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, + (loops_per_jiffy*HZ))); + +} + +/* + * Get CPU information for use by the procfs. + */ + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + char *cpu, *mmu, *fpu; + u_long clockfreq; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + + clockfreq = nasys_clock_freq; + + seq_printf(m, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clocking:\t%lu.%1luMHz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpu, mmu, fpu, + clockfreq/1000000,(clockfreq/100000)%10, + (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, + (loops_per_jiffy*HZ)); + + return 0; +} + +#ifdef CONFIG_NIOS_SPI + +static int bcd2char( int x ) +{ + if ( (x & 0xF) > 0x90 || (x & 0x0F) > 0x09 ) + return 99; + + return (((x & 0xF0) >> 4) * 10) + (x & 0x0F); +} + +#endif // CONFIG_NIOS_SPI + + +void arch_gettod(int *year, int *month, int *date, int *hour, int *min, int *sec) +{ +#ifdef CONFIG_NIOS_SPI + /********************************************************************/ + /* Read the CMOS clock on the Microtronix Datacom O/S Support card. */ + /* Use the SPI driver code, but circumvent the file system by using */ + /* its internal functions. */ + /********************************************************************/ + int hr; + + struct /*********************************/ + { /* The SPI payload. Warning: the */ + unsigned short register_addr; /* sizeof() operator will return */ + unsigned char value; /* a length of 4 instead of 3! */ + } spi_data; /*********************************/ + + + if ( spi_open( NULL, NULL ) ) + { + printk( "Cannot open SPI driver to read system CMOS clock.\n" ); + *year = *month = *date = *hour = *min = *sec = 0; + return; + } + + spi_lseek( NULL, clockCS, 0 /* == SEEK_SET */ ); + + spi_data.register_addr = clock_write_control; + spi_data.value = 0x40; // Write protect + spi_write( NULL, (const char *)&spi_data, 3, NULL ); + + spi_data.register_addr = clock_read_sec; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + *sec = (int)bcd2char( spi_data.value ); + + spi_data.register_addr = clock_read_min; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + *min = (int)bcd2char( spi_data.value ); + + spi_data.register_addr = clock_read_hour; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + hr = (int)bcd2char( spi_data.value ); + if ( hr & 0x40 ) // Check 24-hr bit + hr = (hr & 0x3F) + 12; // Convert to 24-hr + + *hour = hr; + + + + spi_data.register_addr = clock_read_date; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + *date = (int)bcd2char( spi_data.value ); + + spi_data.register_addr = clock_read_month; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + *month = (int)bcd2char( spi_data.value ); + + spi_data.register_addr = clock_read_year; + spi_data.value = 0; + spi_read( NULL, (char *)&spi_data, 3, NULL ); + *year = (int)bcd2char( spi_data.value ); + + + spi_release( NULL, NULL ); +#else + *year = *month = *date = *hour = *min = *sec = 0; + +#endif +} + +static void *cpuinfo_start (struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL; +} + +static void *cpuinfo_next (struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return cpuinfo_start (m, pos); +} + +static void cpuinfo_stop (struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: cpuinfo_start, + next: cpuinfo_next, + stop: cpuinfo_stop, + show: show_cpuinfo +}; + + +// adapted from linux/arch/arm/mach-versatile/core.c and mach-bast +// note, hardware MAC address is still undefined + +#if defined(CONFIG_SMC91X) && defined(na_enet) + +#ifndef LAN91C111_REGISTERS_OFFSET +#define LAN91C111_REGISTERS_OFFSET 0x300 +#endif + +static struct resource smc91x_resources[] = { + [0] = { + .start = na_enet + LAN91C111_REGISTERS_OFFSET, + .end = na_enet + LAN91C111_REGISTERS_OFFSET + 0x100 - 1, // 32bits,64k, LAN91C111_REGISTERS_OFFSET 0x0300 ? + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = na_enet_irq, + .end = na_enet_irq, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +static int __init smc91x_device_init(void) +{ + /* customizes platform devices, or adds new ones */ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(smc91x_device_init); +#endif // CONFIG_SMC91X + + +#if defined(na_DM9000A) && !defined(na_dm9000) // defs for DE2 +#define na_dm9000 na_DM9000A +#define na_dm9000_irq na_DM9000A_irq +#endif + +#if defined(CONFIG_DM9000) && defined(na_dm9000) +#include +static struct resource dm9k_resource[] = { + [0] = { + .start = na_dm9000, + .end = na_dm9000 + 3, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = na_dm9000 + 4, + .end = na_dm9000 + 4 + 3, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = na_dm9000_irq, + .end = na_dm9000_irq, + .flags = IORESOURCE_IRQ, + } + +}; +static struct dm9000_plat_data dm9k_platdata = { + .flags = DM9000_PLATF_16BITONLY, +}; +static struct platform_device dm9k_device = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(dm9k_resource), + .resource = dm9k_resource, + .dev = { + .platform_data = &dm9k_platdata, + } +}; +static int __init dm9k_device_init(void) +{ + /* customizes platform devices, or adds new ones */ + platform_device_register(&dm9k_device); + return 0; +} +arch_initcall(dm9k_device_init); +#endif // CONFIG_DM9000 + + +#if defined(CONFIG_SERIO_ALTPS2) && defined(na_ps2_0) + +static struct resource altps2_0_resources[] = { + [0] = { + .start = na_ps2_0, + .end = na_ps2_0 + 0x8 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = na_ps2_0_irq, + .end = na_ps2_0_irq, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device altps2_0_device = { + .name = "altps2", + .id = 0, + .num_resources = ARRAY_SIZE(altps2_0_resources), + .resource = altps2_0_resources, +}; + +#if defined(na_ps2_1) +static struct resource altps2_1_resources[] = { + [0] = { + .start = na_ps2_1, + .end = na_ps2_1 + 0x8 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = na_ps2_1_irq, + .end = na_ps2_1_irq, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device altps2_1_device = { + .name = "altps2", + .id = 0, + .num_resources = ARRAY_SIZE(altps2_1_resources), + .resource = altps2_1_resources, +}; +#endif // na_ps2_1 + +static int __init altps2_device_init(void) +{ + /* customizes platform devices, or adds new ones */ + platform_device_register(&altps2_0_device); +#if defined(na_ps2_1) + platform_device_register(&altps2_1_device); +#endif // na_ps2_1 + return 0; +} +arch_initcall(altps2_device_init); +#endif // CONFIG_SERIO_ALTPS2 + +#if defined(CONFIG_I2C_GPIO) && defined(na_gpio_0) +#include + +static struct gpio_i2c_pins i2c_gpio_0_pins = { + .sda_pin = (na_gpio_0+(0<<2)), + .scl_pin = (na_gpio_0+(1<<2)), +}; + +static struct platform_device i2c_gpio_0_controller = { + .name = "GPIO-I2C", + .id = 0, + .dev = { + .platform_data = &i2c_gpio_0_pins, + }, + .num_resources = 0 +}; + +static int __init i2c_gpio_device_init(void) +{ + /* customizes platform devices, or adds new ones */ + platform_device_register(&i2c_gpio_0_controller); + return 0; +} +arch_initcall(i2c_gpio_device_init); + +#endif // CONFIG_I2C_GPIO diff --git a/arch/nios2nommu/kernel/signal.c b/arch/nios2nommu/kernel/signal.c new file mode 100644 index 00000000..d8c30dc3 --- /dev/null +++ b/arch/nios2nommu/kernel/signal.c @@ -0,0 +1,738 @@ +/* + * linux/arch/nios2nommu/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * 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. + * + * Linux/m68k support by Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * + * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completely ignored for the emulator + * and the internal floating point format is put on stack) + * + * ++roman (07/09/96): implemented signal stacks (specially for tosemu on + * Atari :-) Current limitation: Only one sigstack can be active at one time. + * If a second signal with SA_ONSTACK set arrives while working on a sigstack, + * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested + * signal handlers! + * + * Jan/20/2004 dgt NiosII + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, + struct rusage * ru); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + old_sigset_t mask = regs->r4; // Verify correct syscall reg + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->r2 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t *unewset = (sigset_t *)regs->r4; + size_t sigsetsize = (size_t)regs->r5; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->r2 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +/* + * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. + */ + + +struct sigframe +{ + char retcode[12]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe +{ + char retcode[12]; + struct siginfo info; + struct ucontext uc; +}; + +#ifdef CONFIG_FPU + +static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ + +static inline int restore_fpu_state(struct sigcontext *sc) +{ + int err = 1; + + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + + if (sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (sc->sc_fpstate[0] != fpu_version) + goto out; + + __asm__ volatile ("Nios II FPU" + : /* no outputs */ + : ); + } + __asm__ volatile ("Nios II FPU" + : : ); + err = 0; + +out: + return err; +} + +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] + +static inline int rt_restore_fpu_state(struct ucontext *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = 0; + fpregset_t fpregs; + int err = 1; + + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + &uc->uc_mcontext.fpregs.f_pcr, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) + goto out; + if (fpstate[0]) { + context_size = fpstate[1]; + + /* Verify the frame format. */ + if (fpstate[0] != fpu_version) + goto out; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto out; + __asm__ volatile ("Nios II FPU" + : /* no outputs */ + : ); + } + if (context_size && + __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, + context_size)) + goto out; + __asm__ volatile ("Nios II FPU" + : : ); + err = 0; + +out: + return err; +} + +#endif + +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, + int *pr2) +{ + int err = 0; + int estatus; + + estatus = regs->estatus; + + /* get previous pt_regs */ + if (copy_from_user(regs, &usc->regs, sizeof(*regs))) + goto badframe; + + /* Prevent user from being able to change + * certain processor status bits. Currently nothing. + */ + regs->estatus = (estatus & 0xffffffff) | (regs->estatus & 0); + + *pr2 = regs->r2; + regs->orig_r2 = -1; /* disable syscall checks */ + +#ifdef CONFIG_FPU + err |= restore_fpu_state(&context); +#endif + + return err; + +badframe: + return 1; +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext *uc, int *pr2) +{ + int temp; + greg_t *gregs = uc->uc_mcontext.gregs; + unsigned long usp; + int err; + + err = __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + err |= __get_user(regs->r1, &gregs[0]); + err |= __get_user(regs->r2, &gregs[1]); + err |= __get_user(regs->r3, &gregs[2]); + err |= __get_user(regs->r4, &gregs[3]); + err |= __get_user(regs->r5, &gregs[4]); + err |= __get_user(regs->r6, &gregs[5]); + err |= __get_user(regs->r7, &gregs[6]); + err |= __get_user(regs->r8, &gregs[7]); + err |= __get_user(regs->r9, &gregs[8]); + err |= __get_user(regs->r10, &gregs[9]); + err |= __get_user(regs->r11, &gregs[10]); + err |= __get_user(regs->r12, &gregs[11]); + err |= __get_user(regs->r13, &gregs[12]); + err |= __get_user(regs->r14, &gregs[13]); + err |= __get_user(regs->r15, &gregs[14]); + err |= __get_user(sw->r16, &gregs[15]); + err |= __get_user(sw->r17, &gregs[16]); + err |= __get_user(sw->r18, &gregs[17]); + err |= __get_user(sw->r19, &gregs[18]); + err |= __get_user(sw->r20, &gregs[19]); + err |= __get_user(sw->r21, &gregs[20]); + err |= __get_user(sw->r22, &gregs[21]); + err |= __get_user(sw->r23, &gregs[22]); + err |= __get_user(usp, &gregs[23]); + err |= __get_user(sw->fp, &gregs[24]); // Verify, should this be settable + err |= __get_user(sw->gp, &gregs[25]); // Verify, should this be settable + + err |= __get_user(temp, &gregs[26]); // Not really necessary no user settable bits + regs->estatus = (regs->estatus & 0xffffffff) | (temp & 0x0); + err |= __get_user(regs->status_extension, + &uc->uc_mcontext.status_extension); + regs->orig_r2 = -1; /* disable syscall checks */ + + if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) + goto badframe; + + *pr2 = regs->r2; + return err; + +badframe: + return 1; +} + +asmlinkage int do_sigreturn(struct pt_regs *regs) +{ + struct sigframe *frame = (struct sigframe *) regs->sp; + sigset_t set; + int rval; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->sc, frame + 1, &rval)) + goto badframe; + return rval; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int do_rt_sigreturn(struct switch_stack *sw) +{ + struct pt_regs *regs = (struct pt_regs *) sw + 1; + struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; // Verify, can we follow the stack back + sigset_t set; + int rval; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (rt_restore_ucontext(regs, sw, &frame->uc, &rval)) + goto badframe; + return rval; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +#ifdef CONFIG_FPU +/* + * Set up a signal frame. + * + * Not converted, no FPU support at moment. + */ + +static inline int save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + int err = 0; + + if (FPU_IS_EMU) { + /* save registers */ + err |= copy_to_user(&sc->sc_fpcntl, current->thread.fpcntl, 12); + err |= copy_to_user(&sc->sc_fpregs, current->thread.fp, 24); + return err; + } + + __asm__ volatile ("Nios II FPUt" + : : ); + + if (sc->sc_fpstate[0]) { + fpu_version = sc->sc_fpstate[0]; + __asm__ volatile ("Nios II FPU" + : /* no outputs */ + : + : ); + } + return err; +} + +static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = 0; + int err = 0; + + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + + __asm__ volatile ("Nios II FPU" + : : : ); + + err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); + if (fpstate[0]) { + fpregset_t fpregs; + context_size = fpstate[1]; + fpu_version = fpstate[0]; + __asm__ volatile ("Nios II FPU" + : /* no outputs */ + : + : ); + err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, + sizeof(fpregs)); + } + if (context_size) + err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, + context_size); + return err; +} + +#endif + +static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + + err |= __put_user(mask, &sc->sc_mask); + err |= copy_to_user(&sc->regs, regs, sizeof(*regs)); +#ifdef CONFIG_FPU + err |= save_fpu_state(sc, regs); +#endif + return err; +} + +static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t *gregs = uc->uc_mcontext.gregs; + int err = 0; + + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + err |= __put_user(regs->status_extension, + &uc->uc_mcontext.status_extension); + err |= __put_user(regs->r1, &gregs[0]); + err |= __put_user(regs->r2, &gregs[1]); + err |= __put_user(regs->r3, &gregs[2]); + err |= __put_user(regs->r4, &gregs[3]); + err |= __put_user(regs->r5, &gregs[4]); + err |= __put_user(regs->r6, &gregs[5]); + err |= __put_user(regs->r7, &gregs[6]); + err |= __put_user(regs->r8, &gregs[7]); + err |= __put_user(regs->r9, &gregs[8]); + err |= __put_user(regs->r10, &gregs[9]); + err |= __put_user(regs->r11, &gregs[10]); + err |= __put_user(regs->r12, &gregs[11]); + err |= __put_user(regs->r13, &gregs[12]); + err |= __put_user(regs->r14, &gregs[13]); + err |= __put_user(regs->r15, &gregs[14]); + err |= __put_user(sw->r16, &gregs[15]); + err |= __put_user(sw->r17, &gregs[16]); + err |= __put_user(sw->r18, &gregs[17]); + err |= __put_user(sw->r19, &gregs[18]); + err |= __put_user(sw->r20, &gregs[19]); + err |= __put_user(sw->r21, &gregs[20]); + err |= __put_user(sw->r22, &gregs[21]); + err |= __put_user(sw->r23, &gregs[22]); + err |= __put_user(regs->sp, &gregs[23]); + err |= __put_user(sw->fp, &gregs[24]); + err |= __put_user(sw->gp, &gregs[25]); +#ifdef CONFIG_FPU + err |= rt_save_fpu_state(uc, regs); +#endif + return err; +} + +extern void cache_push_v (unsigned long vaddr, int len); + +static inline void push_cache (unsigned long vaddr) +{ + cache_push_v(vaddr,12); +} + +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = regs->sp; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)((usp - frame_size) & -8UL); // Verify, is it 32 or 64 bit aligned +} + +static void setup_frame (int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (_NSIG_WORDS > 1) + err |= copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + + /* Set up to return from userspace. */ + regs->ra = (unsigned long) &frame->retcode[0]; + /* movi r3,__NR_sigreturn */ + err |= __put_user(0x00c00004 + (__NR_sigreturn << 6), (long *)(frame->retcode)); + /* mov r2,r0 */ + err |= __put_user(0x0005883a, (long *)(frame->retcode + 4)); + /* trap */ + err |= __put_user(0x003b683a, (long *)(frame->retcode + 8)); + + if (err) + goto give_sigsegv; + + push_cache ((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + regs->sp = (unsigned long) frame; + regs->r4 = (unsigned long) (current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig); + regs->ea = (unsigned long) ka->sa.sa_handler; + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->sp), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= rt_setup_ucontext(&frame->uc, regs); + err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. */ + regs->ra = (unsigned long) &frame->retcode[0]; + /* movi r3,__NR_rt_sigreturn */ + err |= __put_user(0x00c00004 + (__NR_rt_sigreturn << 6), (long *)(frame->retcode)); + /* mov r2,r0 */ + err |= __put_user(0x0005883a, (long *)(frame->retcode + 4)); + /* trap */ + err |= __put_user(0x003b683a, (long *)(frame->retcode + 8)); + + if (err) + goto give_sigsegv; + + push_cache ((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + regs->sp = (unsigned long) frame; + regs->r4 = (unsigned long) (current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig); + regs->r5 = (unsigned long) &frame->info; + regs->r6 = (unsigned long) &frame->uc; + regs->ea = (unsigned long) ka->sa.sa_handler; + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->r2) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->r2 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->r2 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + do_restart: + regs->r2 = regs->orig_r2; + regs->ea -= 4; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + /* are we from a system call? */ + if (regs->orig_r2 >= 0) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + struct k_sigaction ka; + siginfo_t info; + int signr; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + /* FIXME - Do we still need to do this ? */ + current->thread.kregs = regs; + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->orig_r2 >= 0){ + /* Restart the system call - no handlers present */ + if (regs->r2 == -ERESTARTNOHAND + || regs->r2 == -ERESTARTSYS + || regs->r2 == -ERESTARTNOINTR) { + regs->r2 = regs->orig_r2; + regs->ea -= 4; + } else if (regs->r2 == -ERESTART_RESTARTBLOCK) { + regs->r2 = __NR_restart_syscall; + regs->ea -= 4; + } + } + return 0; +} diff --git a/arch/nios2nommu/kernel/start.c b/arch/nios2nommu/kernel/start.c new file mode 100644 index 00000000..62ad6c06 --- /dev/null +++ b/arch/nios2nommu/kernel/start.c @@ -0,0 +1,558 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/start.c + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * May/20/2005 dgt Altera NiosII Custom shift instr(s) + * possibly assumed by memcpy, etc; ensure + * "correct" core loaded therefore if so. + * + ---------------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include + + #ifdef CONFIG_SERIAL_AJUART //;dgt;20may05; + #ifdef CONFIG_SERIAL_AJUART_CONSOLE //;dgt;20may05; + + #include //;dgt;20may05; + #include //;dgt;20may05; + + extern struct console juart_console; //;dgt;20may05; + + #endif // CONFIG_SERIAL_AJUART //;dgt;20may05; + #endif // CONFIG_SERIAL_AJUART_CONSOLE //;dgt;20may05; + +//;dgt;20may05; #ifdef CONFIG_CRC_CHECK + +// #if defined(CONFIG_NIOS_SERIAL) //;dgt;20may05; +// #if defined(CONFIG_NIOS_SERIAL_CONSOLE) //;dgt;20may05; + #if defined(nasys_printf_uart) //;dgt;20may05; + static void putsNoNewLine( unsigned char *s ) + { + while(*s) { + while (!(nasys_printf_uart->np_uartstatus & + np_uartstatus_trdy_mask)); + nasys_printf_uart->np_uarttxdata = *s++; + } + } + + #define NL "\r\n" + static void puts(unsigned char *s) + { + putsNoNewLine( s ); + putsNoNewLine( NL ); + } + #endif // nasys_printf_uart //;dgt;20may05; +// #endif // CONFIG_NIOS_SERIAL_CONSOLE) //;dgt;20may05; +// #endif // CONFIG_NIOS_SERIAL) //;dgt;20may05; + +#ifdef CONFIG_CRC_CHECK //;dgt;20may05; + +#if 1 +#define outchar(X) { \ + while (!(nasys_printf_uart->np_uartstatus & np_uartstatus_trdy_mask)); \ + nasys_printf_uart->np_uarttxdata = (X); } +#else +#define outchar(X) putchar(X) +#endif +#define outhex(X,Y) { \ + unsigned long __w; \ + __w = ((X) >> (Y)) & 0xf; \ + __w = __w > 0x9 ? 'A' + __w - 0xa : '0' + __w; \ + outchar(__w); } +#define outhex8(X) { \ + outhex(X,4); \ + outhex(X,0); } +#define outhex16(X) { \ + outhex(X,12); \ + outhex(X,8); \ + outhex(X,4); \ + outhex(X,0); } +#define outhex32(X) { \ + outhex(X,28); \ + outhex(X,24); \ + outhex(X,20); \ + outhex(X,16); \ + outhex(X,12); \ + outhex(X,8); \ + outhex(X,4); \ + outhex(X,0); } +#endif + +#if 0 +static unsigned long testvar = 0xdeadbeef; +#endif + +#ifdef CONFIG_CRC_CHECK + + +/******************************************************/ + + +extern unsigned long __CRC_Table_Begin; + +typedef unsigned char U8; +typedef unsigned long U32; + +/* Table of CRC-32's of all single byte values */ +const U32 crc_32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +U32 Calc_CRC( const U8 *p, U32 len ) +{ + U32 crc = (U32)~0L; + while (len--) + crc = crc_32_tab[0xFF & (crc ^ *p++)] ^ (crc >> 8); + + return crc ^ (U32)~0L; +} + + + +/******************************************************/ + + +/* hjz: Following time stuff is hacked and modified from uC-libc (various files), which in turn was... */ +/* This is adapted from glibc */ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */ + +#define SECS_PER_HOUR 3600L +#define SECS_PER_DAY 86400L +typedef unsigned long time_t; + + +static const unsigned short int __mon_lengths[2][12] = { + /* Normal years. */ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + /* Leap years. */ + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; +/* This global is exported to the wide world in keeping + * with the interface in time.h */ +long int timezone = 0; + +static const char *dayOfWeek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +# define __isleap(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + +# ifdef __USE_BSD + long int tm_gmtoff; /* Seconds east of UTC. */ + __const char *tm_zone; /* Timezone abbreviation. */ +# else + long int __tm_gmtoff; /* Seconds east of UTC. */ + __const char *__tm_zone; /* Timezone abbreviation. */ +# endif +}; + +void __tm_conv(struct tm *tmbuf, time_t *t, time_t offset) +{ + long days, rem; + register int y; + register const unsigned short int *ip; + + timezone = -offset; + + days = *t / SECS_PER_DAY; + rem = *t % SECS_PER_DAY; + rem += offset; + while (rem < 0) + { + rem += SECS_PER_DAY; + days--; + } + while (rem >= SECS_PER_DAY) + { + rem -= SECS_PER_DAY; + days++; + } + + tmbuf->tm_hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tmbuf->tm_min = rem / 60; + tmbuf->tm_sec = rem % 60; + + /* January 1, 1970 was a Thursday. */ + tmbuf->tm_wday = (4 + days) % 7; + if (tmbuf->tm_wday < 0) + tmbuf->tm_wday += 7; + + y = 1970; + while (days >= (rem = __isleap(y) ? 366 : 365)) + { + y++; + days -= rem; + } + + while (days < 0) + { + y--; + days += __isleap(y) ? 366 : 365; + } + + tmbuf->tm_year = y - 1900; + tmbuf->tm_yday = days; + + ip = __mon_lengths[__isleap(y)]; + for (y = 0; days >= ip[y]; ++y) + days -= ip[y]; + + tmbuf->tm_mon = y; + tmbuf->tm_mday = days + 1; + tmbuf->tm_isdst = -1; +} + + + +/* hjz: NOT your traditional ctime: This one includes timezone */ +/* (UTC) and excludes the traditional trailing newline. */ +char *CTime( time_t *t ) +{ + static char theTime[29]; + struct tm tm; + + __tm_conv( &tm, t, 0 ); + sprintf( theTime, "%s %s %02d %02d:%02d:%02d UTC %04d", + dayOfWeek[tm.tm_wday], month[tm.tm_mon], tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900 ); + + return theTime; +} + +/******************************************************/ + + +/* hjz: polled-I/O: Get a char if one is ready, or return -1 */ +int getc( void ) +{ + if ( nasys_printf_uart->np_uartstatus & np_uartstatus_rrdy_mask ) + return nasys_printf_uart->np_uartrxdata; + else + return -1; +} + + +typedef unsigned long off_t; +typedef struct +{ + U8 *startAddr; + U8 *endAddr; + U32 CRC; + time_t mtime; + off_t size; // File size + char id[44]; // Filename. If path exceeds available size, name is "..." + last 40 chars of given filename + char host[32]; // hostname. If name exceeds available size name is first 28 chars of hostname + "..." +} FLASH_REGION_DESC; + + +int Test_Flash_Regions(void) +{ + FLASH_REGION_DESC *pRegion = (FLASH_REGION_DESC *)&__CRC_Table_Begin; + U32 crc; + char cBuff[256]; + int nrFailedRegions = 0; + int regionStatus; + int i; + unsigned int startAddr = (int) pRegion->startAddr; + unsigned int endAddr = (int) pRegion->endAddr; + + puts( "***Checking flash CRC's" ); + if ( (startAddr == -1) || (startAddr >= endAddr) + || !( ((startAddr >= (int) NIOS_FLASH_START) && (endAddr < (int) NIOS_FLASH_END)) + || ((startAddr >= (int) na_flash) && (endAddr < (int) na_flash_end)) ) ) + { + puts( " No Flash regions defined." ); + return -1; + } + + + for ( i = 0; pRegion->startAddr && pRegion->startAddr != (U8 *)~0L; pRegion++, i++ ) + { + crc = Calc_CRC( pRegion->startAddr, pRegion->endAddr - pRegion->startAddr ); + if ( crc != pRegion->CRC ) + { + regionStatus = 1; + nrFailedRegions++; + } + else + regionStatus = 0; + + sprintf( cBuff, " Region %d: 0x%08lX - 0x%08lX, CRC = 0x%08lX --> %s" NL + " From file `%s' on host `%s'" NL + " Dated %s, size = %lu bytes", + i, (U32)pRegion->startAddr, (U32)pRegion->endAddr, pRegion->CRC, + regionStatus ? "***Failed" : "Passed", + pRegion->id, pRegion->host, CTime( &pRegion->mtime ), pRegion->size + ); + puts( cBuff ); + } + + return nrFailedRegions; +} +#endif /* CONFIG_CRC_CHECK */ + + +int main(void) { + extern void start_kernel(void); + +#if 0 + // extern unsigned long __data_rom_start; + extern unsigned long __data_start; + extern unsigned long __data_end; + extern unsigned long __bss_start; + extern unsigned long __bss_end; + + unsigned long *src; + unsigned long *dest; + unsigned long tmp; +#endif + + +#ifdef DEBUG + puts("MAIN: starting c\n"); +#endif + +#ifdef CONFIG_KGDB /* builtin GDB stub */ + +/* Set up GDB stub, and make the first trap into it */ + nios_gdb_install(1); +#ifdef CONFIG_BREAK_ON_START + puts( "MAIN: trapping to debugger - make sure nios-elf-gdb is running on host." ); + nios_gdb_breakpoint(); + nop(); +#endif + +#endif /* CONFIG_KGDB */ + + +#if 0 + puts("Testing RAM\n"); + + puts("Write...\n"); + for (dest = (unsigned long *)0x40000000; dest < (unsigned long *)0x40080000; dest++) { + *dest = (unsigned long)0x5a5a5a5a ^ (unsigned long)dest; + } + + puts("Read...\n"); + for (dest = (unsigned long *)0x40000000; dest < (unsigned long *)0x40080000; dest++) { + tmp = (unsigned long)0x5a5a5a5a ^ (unsigned long)dest; + if (*dest != tmp) { + puts("Failed."); + outhex32((unsigned long)dest); + puts("is"); + outhex32(*dest); + puts("wrote"); + outhex32(tmp); + while(1); + } + } + + puts("512k RAM\n"); + if (testvar == 0xdeadbeef) puts("Found my key\n"); + else puts("My keys are missing!\n"); + + // src = &__data_rom_start; + src = &__data_start; + dest = &__data_start; + while (dest < &__data_end) *(dest++) = *(src++); + + dest = &__bss_start; + while (dest < &__bss_end) *(dest++) = 0; + + puts("Moved .data\n"); + if (testvar == 0xdeadbeef) puts("Found my key\n"); + else puts("My keys are missing!\n"); + + testvar = 0; +#endif + + +#ifdef CONFIG_CRC_CHECK + #ifdef CONFIG_PROMPT_ON_MISSING_CRC_TABLES + if ( Test_Flash_Regions() ) + #else + if ( Test_Flash_Regions() > 0 ) + #endif + { + int c; + char tmp[3]; + while ( getc() != -1 ) // flush input + ; + + putsNoNewLine( " Do you wish to continue (Y/N) ? " ); + while ( 1 ) + { + c = getc(); + if ( c == -1 ) + continue; + + if ( !isprint( c ) ) + c = '?'; + + sprintf( tmp, "\b%c", c ); + putsNoNewLine( tmp ); + c = toupper( c ); + if ( c == 'Y' ) + { + puts( "" ); + break; + } + + if ( c == 'N' ) + { + puts( NL "***Trapping to monitor..." ); + return -1; + } + } + } + puts( "***Starting kernel..." ); + +#endif + + // Altera NiosII Custom shift instr(s) possibly //;dgt; + // assumed by memcpy, etc; ensure "correct" core //;dgt; + // loaded therefore if so. //;dgt; + + #if defined(ALT_CI_ALIGN_32_N) //;dgt; + if(ALT_CI_ALIGN_32(1, 0xA9876543, //;dgt; + 0xB210FEDC) != 0x10FEDCA9) //;dgt; + { //;dgt; + goto badshiftci_label; //;dgt; + } //;dgt; + if(ALT_CI_ALIGN_32(2, 0xA9876543, //;dgt; + 0xB210FEDC) != 0xFEDCA987) //;dgt; + { //;dgt; + goto badshiftci_label; //;dgt; + } //;dgt; + if(ALT_CI_ALIGN_32(3, 0xA9876543, //;dgt; + 0xB210FEDC) != 0xDCA98765) //;dgt; + { //;dgt; + goto badshiftci_label; //;dgt; + } //;dgt; + #endif //;dgt; + goto gudshiftci_label; //;dgt; +badshiftci_label: //;dgt; + { //;dgt; + unsigned char BadCImsg[] = //;dgt; + "?...ALT_CI_ALIGNn_321() NOT expected" //;dgt; + " NiosII custom instruction\n"; //;dgt; + unsigned char CIabortMsg[] = //;dgt; + " ...aborting uClinux startup..."; //;dgt; + + #ifdef CONFIG_SERIAL_AJUART //;dgt; + #ifdef CONFIG_SERIAL_AJUART_CONSOLE //;dgt; + juart_console.index = 0; //;dgt; + jtaguart_console_write(&(juart_console), //;dgt; + BadCImsg, //;dgt; + strlen(BadCImsg)); //;dgt; + jtaguart_console_write(&(juart_console), //;dgt; + CIabortMsg, //;dgt; + strlen(CIabortMsg)); //;dgt; + #endif // CONFIG_SERIAL_AJUART //;dgt; + #endif // CONFIG_SERIAL_AJUART_CONSOLE //;dgt; + +// #if defined(CONFIG_NIOS_SERIAL) //;dgt; +// #if defined(CONFIG_NIOS_SERIAL_CONSOLE) //;dgt; + #if defined(nasys_printf_uart) //;dgt; + puts(BadCImsg); //;dgt; + puts(CIabortMsg); //;dgt; + #endif // nasys_printf_uart //;dgt; +// #endif // CONFIG_NIOS_SERIAL_CONSOLE) //;dgt; +// #endif // CONFIG_NIOS_SERIAL) //;dgt; + + panic(" ...wrong fpga core?..."); //;dgt; + } //;dgt; + +gudshiftci_label: //;dgt; + + start_kernel(); + return 0; +} diff --git a/arch/nios2nommu/kernel/sys_nios2.c b/arch/nios2nommu/kernel/sys_nios2.c new file mode 100644 index 00000000..7b08c6c4 --- /dev/null +++ b/arch/nios2nommu/kernel/sys_nios2.c @@ -0,0 +1,246 @@ +/* + * linux/arch/nios2nommu/kernel/sys_nios2.c + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/nios2nommu + * platform. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to + * handle more than 4 system call parameters, so these system calls + * used a memory block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); +out: + return error; +} + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) +{ + int version; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + if (copy_from_user (&tmp, + (struct ipc_kludge *)ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + + return -EINVAL; +} + +/* sys_cacheflush -- flush the processor cache. */ +asmlinkage int +sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) +{ + flush_cache_all(); + return(0); +} + +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} + +/* + * Do a system call from kernel instead of calling sys_execve so we + * end up with proper pt_regs. + */ +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +{ + register long __res __asm__ ("r2") = TRAP_ID_SYSCALL; + register long __sc __asm__ ("r3") = __NR_execve; + register long __a __asm__ ("r4") = (long) filename; + register long __b __asm__ ("r5") = (long) argv; + register long __c __asm__ ("r6") = (long) envp; + __asm__ __volatile__ ("trap" : "=r" (__res) + : "0" (__res), "r" (__sc), "r" (__a), "r" (__b), "r" (__c) + : "memory"); + + return __res; +} diff --git a/arch/nios2nommu/kernel/syscalltable.S b/arch/nios2nommu/kernel/syscalltable.S new file mode 100644 index 00000000..a9c96a27 --- /dev/null +++ b/arch/nios2nommu/kernel/syscalltable.S @@ -0,0 +1,322 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/syscalltable.S + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom Ltd + * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 1991, 1992 Linus Torvalds + * + * 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. + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#include +#include +#include +#include + +.text +ALIGN +ENTRY(sys_call_table) + .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_chown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_ni_syscall /* sys_swapon */ + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* was ioperm */ + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall + .long sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long sys_vhangup + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ + .long sys_wait4 + .long sys_ni_syscall /* 115 */ /* sys_swapoff */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_adjtimex + .long sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "creat_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_ni_syscall /* sys_msync */ + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_ni_syscall /* 150 */ /* sys_mlock */ + .long sys_ni_syscall /* sys_munlock */ + .long sys_ni_syscall /* sys_mlockall */ + .long sys_ni_syscall /* sys_munlockall */ + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_ni_syscall /* sys_mremap */ + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize /* sys_getpagesize */ + .long sys_ni_syscall /* old "query_module" */ + .long sys_poll + .long sys_ni_syscall /* sys_nfsservctl */ + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_lchown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_chown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_lchown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_ni_syscall + .long sys_ni_syscall + .long sys_getdents64 /* 220 */ + .long sys_gettid + .long sys_tkill + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr /* 225 */ + .long sys_getxattr + .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr /* 230 */ + .long sys_flistxattr + .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_futex /* 235 */ + .long sys_sendfile64 + .long sys_ni_syscall /* sys_mincore */ + .long sys_ni_syscall /* sys_madvise */ + .long sys_fcntl64 + .long sys_readahead /* 240 */ + .long sys_io_setup + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel /* 245 */ + .long sys_fadvise64 + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 250 */ + .long sys_epoll_wait + .long sys_ni_syscall /* sys_remap_file_pages */ + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 255 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 260 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 265 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy /* 270 */ + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive + .long sys_mq_notify /* 275 */ + .long sys_mq_getsetattr + .long sys_waitid + .long sys_ni_syscall /* sys_setaltroot */ + .long sys_ni_syscall /* sys_add_key */ + .long sys_ni_syscall /* 280 */ /* sys_request_key */ + .long sys_ni_syscall /* sys_keyctl */ + + .rept NR_syscalls - 282 + .long sys_ni_syscall + .endr + diff --git a/arch/nios2nommu/kernel/time.c b/arch/nios2nommu/kernel/time.c new file mode 100644 index 00000000..8f2fb58b --- /dev/null +++ b/arch/nios2nommu/kernel/time.c @@ -0,0 +1,191 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/kernel/time.c + * + * Architecture specific time handling details. + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Most of the stuff is located in the machine specific files. + * + * Copyright (C) 2004 Microtronix Datacom Ltd + * Copyright (C) 1998-2000 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define TICK_SIZE (tick_nsec / 1000) + +unsigned long cpu_khz; +static inline int set_rtc_mmss(unsigned long nowtime) +{ + return -1; +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static irqreturn_t timer_interrupt(int irq, void *dummy) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update=0; + + write_seqlock(&xtime_lock); + na_timer0->np_timerstatus = 0; /* Clear the interrupt condition */ + + do_timer(1); +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif + profile_tick(CPU_PROFILING); + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (ntp_synced() && xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } + + write_sequnlock(&xtime_lock); + return(IRQ_HANDLED); +} + +void time_init(void) +{ + unsigned int year, mon, day, hour, min, sec; + + extern void arch_gettod(int *year, int *mon, int *day, int *hour, + int *min, int *sec); + + cpu_khz=nasys_clock_freq_1000; + arch_gettod(&year, &mon, &day, &hour, &min, &sec); + + if ((year += 1900) < 1970) + year += 100; + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_nsec = 0; + wall_to_monotonic.tv_sec = -xtime.tv_sec; + + request_irq(na_timer0_irq, timer_interrupt, IRQ_FLG_LOCK, "timer", NULL); + + na_timer0->np_timerperiodl = (nasys_clock_freq/HZ)-1; + na_timer0->np_timerperiodh = ((nasys_clock_freq/HZ)-1) >> 16; + + /* interrupt enable + continuous + start */ + na_timer0->np_timercontrol = np_timercontrol_start_mask + + np_timercontrol_cont_mask + + np_timercontrol_ito_mask; +} + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long seq; + unsigned long usec, sec; + + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + usec = 0; // For now use timeoffset 0 +// usec = mach_gettimeoffset ? mach_gettimeoffset() : 0; + sec = xtime.tv_sec; + usec += (xtime.tv_nsec / 1000); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * made, and then undo it! + * FIXME On m68knommu this is if (mach_gettimeoffset) nsec -= (mach_gettimeoffset() * 1000); + */ +// nsec -= cur_timer->get_offset() * NSEC_PER_USEC; +// nsec -= (jiffies - wall_jiffies) * TICK_NSEC; + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + return 0; +} + + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + +EXPORT_SYMBOL(do_gettimeofday); +EXPORT_SYMBOL(do_settimeofday); diff --git a/arch/nios2nommu/kernel/traps.c b/arch/nios2nommu/kernel/traps.c new file mode 100644 index 00000000..14b7e4ca --- /dev/null +++ b/arch/nios2nommu/kernel/traps.c @@ -0,0 +1,178 @@ +/* + * arch/niosnommu/kernel/traps.c + * + * Copyright 2004 Microtronix Datacom Ltd. + * Copyright 2001 Vic Phillips + * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) + * + * hacked from: + * + * arch/sparcnommu/kernel/traps.c + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include /* for jiffies */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* #define TRAP_DEBUG */ + +#if 0 +void dumpit(unsigned long l1, unsigned long l2) +{ + printk("0x%08x l1 0x%08x l2\n"); + while(1); +} + +struct trap_trace_entry { + unsigned long pc; + unsigned long type; +}; + +int trap_curbuf = 0; +struct trap_trace_entry trapbuf[1024]; + +void syscall_trace_entry(struct pt_regs *regs) +{ + printk("%s[%d]: ", current->comm, current->pid); + printk("scall<%d> (could be %d)\n", (int) regs->r3, + (int) regs->r4); +} + +void syscall_trace_exit(struct pt_regs *regs) +{ +} +#endif + +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_stack(current, &stack); +} + +EXPORT_SYMBOL(dump_stack); + +/* + * The show_stack is an external API which we do not use ourselves. + * The oops is printed in die_if_kernel. + */ + +int kstack_depth_to_print = 48; + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *endstack, addr; + extern char _start, _etext; + int i; + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.ksp; + else + stack = (unsigned long *)&stack; + } + + addr = (unsigned long) stack; + endstack = (unsigned long *) PAGE_ALIGN(addr); + + printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i % 8 == 0) + printk(KERN_EMERG "\n "); + printk(KERN_EMERG " %08lx", *stack++); + } + + printk(KERN_EMERG "\nCall Trace:"); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_start) && + (addr <= (unsigned long) &_etext))) { + if (i % 4 == 0) + printk(KERN_EMERG "\n "); + printk(KERN_EMERG " [<%08lx>]", addr); + i++; + } + } + printk(KERN_EMERG "\n"); +} + +void die_if_kernel(char *str, struct pt_regs *pregs) +{ + unsigned long pc; + + pc = pregs->ra; + printk("0x%08lx\n trapped to die_if_kernel\n",pregs->ra); + show_regs(pregs); + if(pregs->status_extension & PS_S) + do_exit(SIGKILL); + do_exit(SIGSEGV); +} + +void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) +{ + if(type < 0x10) { + printk("Unimplemented Nios2 TRAP, type = %02lx\n", type); + die_if_kernel("Whee... Hello Mr. Penguin", current->thread.kregs); + } +} + +#if 0 +void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long psr) +{ +#ifdef TRAP_DEBUG + printk("Watchpoint detected at PC %08lx PSR %08lx\n", pc, psr); +#endif + if(psr & PSR_SUPERVISOR) + panic("Tell me what a watchpoint trap is, and I'll then deal " + "with such a beast..."); +} +#endif + +void trap_init(void) +{ +#ifdef DEBUG + printk("trap_init reached\n"); +#endif +} diff --git a/arch/nios2nommu/kernel/usb.c b/arch/nios2nommu/kernel/usb.c new file mode 100644 index 00000000..777eb507 --- /dev/null +++ b/arch/nios2nommu/kernel/usb.c @@ -0,0 +1,354 @@ +/* + * arch/nios2nommu/kernel/usb.c -- platform level USB initialization + * + * 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 + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_USB_SL811_HCD) || defined (CONFIG_USB_SL811_HCD_MODULE) +#if defined(CONFIG_MICROTRONIX_STRATIX) || defined (CONFIG_MICROTRONIX_CYCLONE) + +#include +#define SL811_ADDR ((unsigned int)na_usb) +#define SL811_IRQ na_usb_irq + +static void sl811_port_power(struct device *dev, int is_on) +{ +} + +static void sl811_port_reset(struct device *dev) +{ + writeb(0xA, (SL811_ADDR+8)); + mdelay(10); + writeb(4, (SL811_ADDR+8)); +} + +static struct resource sl811hs_resources[] = { + { + .start = (SL811_ADDR), + .end = (SL811_ADDR + 3), + .flags = IORESOURCE_MEM, + }, + { + .start = (SL811_ADDR + 4), + .end = (SL811_ADDR + 7), + .flags = IORESOURCE_MEM, + }, + { + .start = SL811_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sl811_platform_data sl811_data = { + .can_wakeup = 0, + .potpg = 0, + .power = 250, + .port_power = sl811_port_power, + .reset = sl811_port_reset, +}; + +static struct platform_device sl811hs_device = { + .name = "sl811-hcd", + .id = -1, + .dev = { + //.release = usb_release, + //.dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + .platform_data = &sl811_data, + }, + .num_resources = ARRAY_SIZE(sl811hs_resources), + .resource = sl811hs_resources, +}; + + +static int __init mtx_kit_usb_init(void) +{ + int status; + + status = platform_device_register(&sl811hs_device); + if (status) { + pr_debug("can't register sl811hs device, %d\n", status); + return -1; + } + + writeb(4, (SL811_ADDR+8)); + return 0; +} + +subsys_initcall(mtx_kit_usb_init); +#endif /* (CONFIG_MICROTRONIX_STRATIX) || (CONFIG_MICROTRONIX_CYCLONE)*/ +#endif /*(CONFIG_USB_SL811_HCD) ||(CONFIG_USB_SL811_HCD_MODULE) */ + +#if defined(CONFIG_USB_ISP116X_HCD) || defined (CONFIG_USB_ISP116X_HCD_MODULE) + +#include + +#define ISP116X_HCD_ADDR ((unsigned int)na_usb) +#define ISP116X_HCD_IRQ na_usb_irq + +static void isp116x_delay(struct device *dev, int delay) +{ + ndelay(delay); +} + +static struct resource isp116x_hcd_resources[] = { + { + .start = (ISP116X_HCD_ADDR), + .end = (ISP116X_HCD_ADDR + 3), + .flags = IORESOURCE_MEM, + }, + { + .start = (ISP116X_HCD_ADDR + 4), + .end = (ISP116X_HCD_ADDR + 7), + .flags = IORESOURCE_MEM, + }, + { + .start = ISP116X_HCD_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct isp116x_platform_data isp116x_data = { + // Enable internal resistors on downstream ports + .sel15Kres = 0, + // Clock cannot be stopped + .clknotstop = 1, + // On-chip overcurrent protection + .oc_enable = 0, + // INT output polarity + .int_act_high = 0, + // INT edge or level triggered + .int_edge_triggered = 0, + // End-of-transfer input polarity + .eot_act_high = 0, + // DREQ output polarity + .dreq_act_high = 1, + // WAKEUP pin connected + .remote_wakeup_connected= 0, + // Wakeup by devices on usb bus enabled + .remote_wakeup_enable = 0, + // Switch or not to switch (keep always powered) + .no_power_switching = 1, + // Ganged port power switching (0) or individual port power switching (1) + .power_switching_mode = 0, + .reset = NULL /* isp116x_reset */, + .delay = isp116x_delay, +}; + +static struct platform_device isp116x_hcd = { + .name = "isp116x-hcd", + .id = -1, + .dev = { + //.release = usb_release, + //.dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + .platform_data = &isp116x_data, + }, + .num_resources = ARRAY_SIZE(isp116x_hcd_resources), + .resource = isp116x_hcd_resources, +}; + +static int __init usb_hcd_init(void) +{ + int status; + + status = platform_device_register(&isp116x_hcd); + if (status) { + pr_debug("can't register isp116x host controller, %d\n", status); + return -1; + } + + return 0; +} +subsys_initcall(usb_hcd_init); +#endif /*(CONFIG_USB_ISP116X_HCD) ||(CONFIG_USB_ISP116X_HCD_MODULE) */ + +#if defined(CONFIG_USB_ISP1161X) || defined(CONFIG_USB_ISP1161X_MODULE) +#include + +#define ISP116X_UDC_ADDR ((unsigned int)na_usb+8) +#define ISP116X_UDC_IRQ na_int2_usb_irq + +static struct resource isp116x_udc_resources[] = { + { + .start = (ISP116X_UDC_ADDR), + .end = (ISP116X_UDC_ADDR + 3), + .flags = IORESOURCE_MEM, + }, + { + .start = (ISP116X_UDC_ADDR + 4), + .end = (ISP116X_UDC_ADDR + 7), + .flags = IORESOURCE_MEM, + }, + { + .start = ISP116X_UDC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static void isp116x_udc_delay() +{ + __asm__ __volatile__( + "1: \n\t" + " beq %0,zero,2f\n\t" + " addi %0, %0, -1\n\t" + " br 1b\n\t" + "2: \n\t" + : + : "r" (nasys_clock_freq_1000 * 180 / 2000000) + ); + +} +struct isp116x_dc_platform_data isp116x_udc_data = { + .ext_pullup_enable =0, + .no_lazy =1, + .eot_act_high =0, + .remote_wakeup_enable=1, + .power_off_enable =1, + .int_edge_triggered =0, + .int_act_high =0, + .clkout_freq =12, + .delay = isp116x_udc_delay +}; + +static struct platform_device isp116x_udc = { + .name = "isp1161a_udc", + .id = -1, + .dev = { + //.release = usb_release, + //.dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + .platform_data = &isp116x_udc_data, + }, + .num_resources = ARRAY_SIZE(isp116x_udc_resources), + .resource = isp116x_udc_resources, +}; + +static int __init usb_udc_init(void) +{ + int status; + np_pio* pio; + + status = platform_device_register(&isp116x_udc); + if (status) { + pr_debug("can't register isp116x device controller, %d\n", status); + return -1; + } + + /* enable interrupts */ + pio = (np_pio*)na_int2_usb; + //outw(0, &pio->np_piodata); + //outw(0, &pio->np_pioedgecapture); + outw(1, &pio->np_piointerruptmask); + + return 0; +} +subsys_initcall(usb_udc_init); +#endif + +#if defined(na_ISP1362_avalonS) // for DE2 dev board, FIX ME otehrwise +#define na_usb na_ISP1362_avalonS +#define na_usb_irq na_ISP1362_avalonS_irq +#endif + +#if defined(na_ISP1362_avalon_slave_0) // for DE2 dev board, FIX ME otehrwise +#define na_usb na_ISP1362_avalon_slave_0 +#define na_usb_irq na_ISP1362_avalon_slave_0_irq +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) && defined(na_usb) + +#include +#define ISP1362_HCD_ADDR ((unsigned int)na_usb) +#define ISP1362_HCD_IRQ na_usb_irq + +static struct resource isp1362_hcd_resources[] = { + { + .start = (ISP1362_HCD_ADDR), + .end = (ISP1362_HCD_ADDR + 3), + .flags = IORESOURCE_MEM, + }, + { + .start = (ISP1362_HCD_ADDR + 4), + .end = (ISP1362_HCD_ADDR + 7), + .flags = IORESOURCE_MEM, + }, + { + .start = ISP1362_HCD_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct isp1362_platform_data isp1362_data = { + // Enable internal resistors on downstream ports + .sel15Kres = 1, + // Clock cannot be stopped + .clknotstop = 0, + // On-chip overcurrent protection + .oc_enable = 0, + // INT output polarity + .int_act_high = 0, + // INT edge or level triggered + .int_edge_triggered = 0, + // WAKEUP pin connected + .remote_wakeup_connected = 0, + // Switch or not to switch (keep always powered) + .no_power_switching = 1, + // Ganged port power switching (0) or individual port power switching (1) + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd = { + .name = "isp1362-hcd", + .id = -1, + .dev = { + //.release = usb_release, + //.dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0x0fffffff, + .platform_data = &isp1362_data, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; + +static int __init usb_hcd_init(void) +{ + int status; + + status = platform_device_register(&isp1362_hcd); + if (status) { + pr_debug("can't register isp1362 host controller, %d\n", status); + return -1; + } + + return 0; +} +subsys_initcall(usb_hcd_init); +#endif + diff --git a/arch/nios2nommu/lib/Makefile b/arch/nios2nommu/lib/Makefile new file mode 100644 index 00000000..1315c579 --- /dev/null +++ b/arch/nios2nommu/lib/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (C) 2005 Microtronix Datacom Ltd +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Library 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 Library General Public License for more +# details. + +####CSRC := $(wildcard *.c) +####lib-y =$(patsubst %.c,%.o, $(CSRC)) +####wapos! +lib-y =checksum.o string.o memcpy.o diff --git a/arch/nios2nommu/lib/checksum.c b/arch/nios2nommu/lib/checksum.c new file mode 100644 index 00000000..475f1a31 --- /dev/null +++ b/arch/nios2nommu/lib/checksum.c @@ -0,0 +1,73 @@ +/*-------------------------------------------------------------------- + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#include +#include + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ + +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) +{ +#if 0 + __asm__ __volatile__ ...//;dgt2;tmp;not (yet) available... + ...//;dgt2;tmp;NiosI didn't offer either... +#else + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return result; +#endif +} + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +/* + * the same as csum_partial, but copies from fs:src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); + +} diff --git a/arch/nios2nommu/lib/memcpy.c b/arch/nios2nommu/lib/memcpy.c new file mode 100644 index 00000000..6586b99a --- /dev/null +++ b/arch/nios2nommu/lib/memcpy.c @@ -0,0 +1,62 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/lib/memcpy.c + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jun/09/2004 dgt Split out separate source file from string.c + * + ---------------------------------------------------------------------*/ + +#include +#include +#include +#include + +#ifdef __HAVE_ARCH_MEMCPY + void * memcpy(void * d, const void * s, size_t count) + { + unsigned long dst, src; + dst = (unsigned long) d; + src = (unsigned long) s; + + if ((count < 8) || ((dst ^ src) & 3)) + goto restup; + + if (dst & 1) { + *(char*)dst++=*(char*)src++; + count--; + } + if (dst & 2) { + *(short*)dst=*(short*)src; + src += 2; + dst += 2; + count -= 2; + } + while (count > 3) { + *(long*)dst=*(long*)src; + src += 4; + dst += 4; + count -= 4; + } + + restup: + while (count--) + *(char*)dst++=*(char*)src++; + + return d; + } +#endif diff --git a/arch/nios2nommu/lib/string.c b/arch/nios2nommu/lib/string.c new file mode 100644 index 00000000..b87c195e --- /dev/null +++ b/arch/nios2nommu/lib/string.c @@ -0,0 +1,180 @@ +/*-------------------------------------------------------------------- + * + * arch/nios2nommu/lib/string.c + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * Jun/09/2004 dgt Split out memcpy into separate source file + * + ---------------------------------------------------------------------*/ + +#include +#include +#include +#include + +#ifdef __HAVE_ARCH_MEMSET +void * memset(void * s,int c,size_t count) +{ + + if (count > 8) { + int destptr, charcnt, dwordcnt, fill8reg, wrkrega; + __asm__ __volatile__ ( + // fill8 %3, %5 (c & 0xff)\n\t" + // + " slli %4, %5, 8\n\t" + " or %4, %4, %5\n\t" + " slli %3, %4, 16\n\t" + " or %3, %3, %4\n\t" + // + // Word-align %0 (s) if necessary + // + " andi %4, %0, 0x01\n\t" + " beq %4, zero, 1f\n\t" + " addi %1, %1, -1\n\t" + " stb %3, 0(%0)\n\t" + " addi %0, %0, 1\n\t" + "1: \n\t" + " mov %2, %1\n\t" + // + // Dword-align %0 (s) if necessary + // + " andi %4, %0, 0x02\n\t" + " beq %4, zero, 2f\n\t" + " addi %1, %1, -2\n\t" + " sth %3, 0(%0)\n\t" + " addi %0, %0, 2\n\t" + " mov %2, %1\n\t" + "2: \n\t" + // %1 and %2 are how many more bytes to set + // + " srli %2, %2, 2\n\t" + // + // %2 is how many dwords to set + // + "3: ;\n\t" + " stw %3, 0(%0)\n\t" + " addi %0, %0, 4\n\t" + " addi %2, %2, -1\n\t" + " bne %2, zero, 3b\n\t" + // + // store residual word and/or byte if necessary + // + " andi %4, %1, 0x02\n\t" + " beq %4, zero, 4f\n\t" + " sth %3, 0(%0)\n\t" + " addi %0, %0, 2\n\t" + "4: \n\t" + // store residual byte if necessary + // + " andi %4, %1, 0x01\n\t" + " beq %4, zero, 5f\n\t" + " stb %3, 0(%0)\n\t" + "5: \n\t" + + : "=r" (destptr), /* %0 Output */ + "=r" (charcnt), /* %1 Output */ + "=r" (dwordcnt), /* %2 Output */ + "=r" (fill8reg), /* %3 Output */ + "=r" (wrkrega) /* %4 Output */ + + : "r" (c & 0xff), /* %5 Input */ + "0" (s), /* %0 Input/Output */ + "1" (count) /* %1 Input/Output */ + + : "memory" /* clobbered */ + ); + } + else { + char* xs=(char*)s; + while (count--) + *xs++ = c; + } + return s; +} +#endif + +#ifdef __HAVE_ARCH_MEMMOVE +void * memmove(void * d, const void * s, size_t count) +{ + unsigned long dst, src; + + if (d < s) { + dst = (unsigned long) d; + src = (unsigned long) s; + + if ((count < 8) || ((dst ^ src) & 3)) + goto restup; + + if (dst & 1) { + *(char*)dst++=*(char*)src++; + count--; + } + if (dst & 2) { + *(short*)dst=*(short*)src; + src += 2; + dst += 2; + count -= 2; + } + while (count > 3) { + *(long*)dst=*(long*)src; + src += 4; + dst += 4; + count -= 4; + } + + restup: + while (count--) + *(char*)dst++=*(char*)src++; + } else { + dst = (unsigned long) d + count; + src = (unsigned long) s + count; + + if ((count < 8) || ((dst ^ src) & 3)) + goto restdown; + + if (dst & 1) { + src--; + dst--; + count--; + *(char*)dst=*(char*)src; + } + if (dst & 2) { + src -= 2; + dst -= 2; + count -= 2; + *(short*)dst=*(short*)src; + } + while (count > 3) { + src -= 4; + dst -= 4; + count -= 4; + *(long*)dst=*(long*)src; + } + + restdown: + while (count--) { + src--; + dst--; + *(char*)dst=*(char*)src; + } + } + + return d; + +} +#endif diff --git a/arch/nios2nommu/mm/Makefile b/arch/nios2nommu/mm/Makefile new file mode 100644 index 00000000..b007a113 --- /dev/null +++ b/arch/nios2nommu/mm/Makefile @@ -0,0 +1,12 @@ +# $Id: Makefile,v 1.1 2006/07/05 06:23:18 gerg Exp $ +# Makefile for the linux Sparc-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +obj-y := init.o ioremap.o extable.o memory.o +obj-y += dma-noncoherent.o + diff --git a/arch/nios2nommu/mm/dma-noncoherent.c b/arch/nios2nommu/mm/dma-noncoherent.c new file mode 100644 index 00000000..56499401 --- /dev/null +++ b/arch/nios2nommu/mm/dma-noncoherent.c @@ -0,0 +1,373 @@ +/* + * 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. + * + * Copyright (C) 2000 Ani Joshi + * Copyright (C) 2000, 2001 Ralf Baechle + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#define UNCAC_ADDR(addr) ((void *)((unsigned long)(addr) | 0x80000000)) +#define CAC_ADDR(addr) ((void *)((unsigned long)(addr) & ~0x80000000)) + +/* + * Warning on the terminology - Linux calls an uncached area coherent; + * MIPS terminology calls memory areas with hardware maintained coherency + * coherent. + */ + +void *dma_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp) +{ + void *ret; + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_phys(ret); + } + + return ret; +} + +EXPORT_SYMBOL(dma_alloc_noncoherent); + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp) +{ + void *ret; + + ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); + if (ret) { + dma_cache_wback_inv((unsigned long) ret, size); + ret = UNCAC_ADDR(ret); + } + + return ret; +} + +EXPORT_SYMBOL(dma_alloc_coherent); + +void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + free_pages((unsigned long) vaddr, get_order(size)); +} + +EXPORT_SYMBOL(dma_free_noncoherent); + +void dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + unsigned long addr = (unsigned long) vaddr; + + addr = (unsigned long) CAC_ADDR(addr); + free_pages(addr, get_order(size)); +} + +EXPORT_SYMBOL(dma_free_coherent); + +static inline void __dma_sync(unsigned long addr, size_t size, + enum dma_data_direction direction) +{ + switch (direction) { + case DMA_TO_DEVICE: + dma_cache_wback(addr, size); + break; + + case DMA_FROM_DEVICE: + dma_cache_inv(addr, size); + break; + + case DMA_BIDIRECTIONAL: + dma_cache_wback_inv(addr, size); + break; + + default: + BUG(); + } +} + +dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction) +{ + unsigned long addr = (unsigned long) ptr; + + __dma_sync(addr, size, direction); + + return virt_to_phys(ptr); +} + +EXPORT_SYMBOL(dma_map_single); + +void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + unsigned long addr; + addr = dma_addr + PAGE_OFFSET; + + //__dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_unmap_single); + +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + for (i = 0; i < nents; i++, sg++) { + unsigned long addr; + + addr = (unsigned long) page_address(sg->page); + if (addr) { + __dma_sync(addr + sg->offset, sg->length, direction); + sg->dma_address = (dma_addr_t)page_to_phys(sg->page) + + sg->offset; + } + } + + return nents; +} + +EXPORT_SYMBOL(dma_map_sg); + +dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, size); + + return page_to_phys(page) + offset; +} + +EXPORT_SYMBOL(dma_map_page); + +void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (direction != DMA_TO_DEVICE) { + unsigned long addr; + + addr = dma_address + PAGE_OFFSET; + dma_cache_wback_inv(addr, size); + } +} + +EXPORT_SYMBOL(dma_unmap_page); + +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + unsigned long addr; + int i; + + BUG_ON(direction == DMA_NONE); + + if (direction == DMA_TO_DEVICE) + return; + + for (i = 0; i < nhwentries; i++, sg++) { + addr = (unsigned long) page_address(sg->page); + if (addr) + __dma_sync(addr + sg->offset, sg->length, direction); + } +} + +EXPORT_SYMBOL(dma_unmap_sg); + +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_for_cpu); + +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + offset + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + offset + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_range_for_device); + +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for (i = 0; i < nelems; i++, sg++) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); +} + +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for (i = 0; i < nelems; i++, sg++) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); +} + +EXPORT_SYMBOL(dma_sync_sg_for_device); + +int dma_mapping_error(dma_addr_t dma_addr) +{ + return 0; +} + +EXPORT_SYMBOL(dma_mapping_error); + +int dma_supported(struct device *dev, u64 mask) +{ + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if (mask < 0x00ffffff) + return 0; + + return 1; +} + +EXPORT_SYMBOL(dma_supported); + +int dma_is_consistent(dma_addr_t dma_addr) +{ + return 1; +} + +EXPORT_SYMBOL(dma_is_consistent); + +void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction) +{ + if (direction == DMA_NONE) + return; + + dma_cache_wback_inv((unsigned long)vaddr, size); +} + +EXPORT_SYMBOL(dma_cache_sync); + +/* The DAC routines are a PCIism.. */ + +#ifdef CONFIG_PCI + +#include + +dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, + struct page *page, unsigned long offset, int direction) +{ + return (dma64_addr_t)page_to_phys(page) + offset; +} + +EXPORT_SYMBOL(pci_dac_page_to_dma); + +struct page *pci_dac_dma_to_page(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return mem_map + (dma_addr >> PAGE_SHIFT); +} + +EXPORT_SYMBOL(pci_dac_dma_to_page); + +unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return dma_addr & ~PAGE_MASK; +} + +EXPORT_SYMBOL(pci_dac_dma_to_offset); + +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); + +#endif /* CONFIG_PCI */ diff --git a/arch/nios2nommu/mm/extable.c b/arch/nios2nommu/mm/extable.c new file mode 100644 index 00000000..e23778fe --- /dev/null +++ b/arch/nios2nommu/mm/extable.c @@ -0,0 +1,29 @@ +/* + * linux/arch/niosnommu/mm/extable.c + */ + +#include +#include +#include + +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return NULL; +} diff --git a/arch/nios2nommu/mm/init.c b/arch/nios2nommu/mm/init.c new file mode 100644 index 00000000..3824d999 --- /dev/null +++ b/arch/nios2nommu/mm/init.c @@ -0,0 +1,233 @@ +/* + * linux/arch/nios2nommu/mm/init.c + * + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * Based on: + * + * linux/arch/m68k/mm/init.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com) + * DEC/2000 -- linux 2.4 support + * Jan/20/2004 dgt NiosII + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +//;dgt2;#include +//;dgt2;#include + +#undef DEBUG + +extern void die_if_kernel(char *,struct pt_regs *,long); +extern void free_initmem(void); + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +static unsigned long empty_bad_page_table; + +static unsigned long empty_bad_page; + +unsigned long empty_zero_page; + +extern unsigned long rom_length; + +void show_mem(void) +{ + unsigned long i; + int free = 0, total = 0, reserved = 0, shared = 0; + int cached = 0; + + printk(KERN_INFO "\nMem-info:\n"); + show_free_areas(); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else + shared += page_count(mem_map+i) - 1; + } + printk(KERN_INFO "%d pages of RAM\n",total); + printk(KERN_INFO "%d free pages\n",free); + printk(KERN_INFO "%d reserved pages\n",reserved); + printk(KERN_INFO "%d pages shared\n",shared); + printk(KERN_INFO "%d pages swap cached\n",cached); +} + +extern unsigned long memory_start; +extern unsigned long memory_end; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void paging_init(void) +{ + /* + * Make sure start_mem is page aligned, otherwise bootmem and + * page_alloc get different views of the world. + */ +#ifdef DEBUG + unsigned long start_mem = PAGE_ALIGN(memory_start); +#endif + unsigned long end_mem = memory_end & PAGE_MASK; + +#ifdef DEBUG + printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + /* + * Initialize the bad page table and bad page to point + * to a couple of allocated pages. + */ + empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * Set up SFC/DFC registers (user data space). + */ + set_fs (USER_DS); + +#ifdef DEBUG + printk (KERN_DEBUG "before free_area_init\n"); + + printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + { + unsigned long zones_size[MAX_NR_ZONES] = {0, }; + + zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; + zones_size[ZONE_NORMAL] = 0; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = 0; +#endif + free_area_init(zones_size); + } +} + +void mem_init(void) +{ + int codek = 0, datak = 0, initk = 0; + unsigned long tmp; + extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end; + extern unsigned char _ramend, _rambase; + unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */ + unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */ + +#ifdef DEBUG + printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); +#endif + + end_mem &= PAGE_MASK; + high_memory = (void *) end_mem; + + start_mem = PAGE_ALIGN(start_mem); + max_mapnr = num_physpages = MAP_NR(high_memory); + + /* this will put all memory onto the freelists */ + totalram_pages = free_all_bootmem(); + + codek = (&_etext - &_stext) >> 10; + datak = (&_ebss - &_sdata) >> 10; + initk = (&__init_begin - &__init_end) >> 10; + + tmp = nr_free_pages() << PAGE_SHIFT; + printk(KERN_INFO "Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n", + tmp >> 10, + (&_ramend - &_rambase) >> 10, + (rom_length > 0) ? ((rom_length >> 10) - codek) : 0, + rom_length >> 10, + codek, + datak + ); +} + + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + int pages = 0; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + init_page_count(virt_to_page(start)); + free_page(start); + totalram_pages++; + pages++; + } + printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages); +} +#endif + +void +free_initmem() +{ +#ifdef CONFIG_RAMKERNEL + unsigned long addr; + extern char __init_begin, __init_end; + /* + * The following code should be cool even if these sections + * are not page aligned. + */ + addr = PAGE_ALIGN((unsigned long)(&__init_begin)); + /* next to check that the page we free is not a partial page */ + for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } + printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", + (addr - PAGE_ALIGN((long) &__init_begin)) >> 10, + (int)(PAGE_ALIGN((unsigned long)(&__init_begin))), + (int)(addr - PAGE_SIZE)); +#endif +} + diff --git a/arch/nios2nommu/mm/ioremap.c b/arch/nios2nommu/mm/ioremap.c new file mode 100644 index 00000000..1c8b172a --- /dev/null +++ b/arch/nios2nommu/mm/ioremap.c @@ -0,0 +1,65 @@ +/* linux/arch/nios2nommu/mm/ioremap.c, based on: + * + * linux/arch/m68knommu/mm/kmap.c + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 2000 Lineo, + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Map some physical address range into the kernel address space. + */ + +void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) +{ + return (void *)physaddr; +} + +/* + * Unmap a ioremap()ed region again + */ +void iounmap(void *addr) +{ +} + +/* + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wans't used anyway and might be added later. + */ +void __iounmap(void *addr, unsigned long size) +{ +} + diff --git a/arch/nios2nommu/mm/memory.c b/arch/nios2nommu/mm/memory.c new file mode 100644 index 00000000..b2ffdf16 --- /dev/null +++ b/arch/nios2nommu/mm/memory.c @@ -0,0 +1,225 @@ +/* + * linux/arch/nio2nommu/mm/memory.c + * + * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 1998 Kenneth Albanowski , + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * Based on: + * + * linux/arch/m68k/mm/memory.c + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * cache_clear() semantics: Clear any cache entries for the area in question, + * without writing back dirty entries first. This is useful if the data will + * be overwritten anyway, e.g. by DMA to memory. The range is defined by a + * _physical_ address. + */ + +void cache_clear (unsigned long paddr, int len) +{ +} + + +/* + * Define cache invalidate functions. The instruction and data cache + * will need to be flushed. Write back the dirty data cache and invalidate + * the instruction cache for the range. + * + */ + +static __inline__ void cache_invalidate_inst(unsigned long paddr, int len) +{ + unsigned long sset, eset; + + sset = (paddr & (nasys_icache_size - 1)) & (~(nasys_icache_line_size - 1)); + eset = (((paddr & (nasys_icache_size - 1)) + len) & (~(nasys_icache_line_size - 1))) + nasys_icache_line_size; + + __asm__ __volatile__ ( + "1:\n\t" + "flushi %0\n\t" + "add %0,%0,%2\n\t" + "blt %0,%1,1b\n\t" + "flushp\n\t" + : : "r" (sset), "r" (eset), "r" (nasys_icache_line_size)); + +} + +static __inline__ void cache_invalidate_data(unsigned long paddr, int len) +{ + unsigned long sset, eset; + + sset = (paddr & (nasys_dcache_size - 1)) & (~(nasys_dcache_line_size - 1)); + eset = (((paddr & (nasys_dcache_size - 1)) + len) & (~(nasys_dcache_line_size - 1))) + nasys_dcache_line_size; + + __asm__ __volatile__ ( + "1:\n\t" + "flushd 0(%0)\n\t" + "add %0,%0,%2\n\t" + "blt %0,%1,1b\n\t" + : : "r" (sset),"r" (eset), "r" (nasys_dcache_line_size)); + +} + +static __inline__ void cache_invalidate_lines(unsigned long paddr, int len) +{ + unsigned long sset, eset; + + sset = (paddr & (nasys_dcache_size - 1)) & (~(nasys_dcache_line_size - 1)); + eset = (((paddr & (nasys_dcache_size - 1)) + len) & (~(nasys_dcache_line_size - 1))) + nasys_dcache_line_size; + + __asm__ __volatile__ ( + "1:\n\t" + "flushd 0(%0)\n\t" + "add %0,%0,%2\n\t" + "blt %0,%1,1b\n\t" + : : "r" (sset),"r" (eset), "r" (nasys_dcache_line_size)); + + sset = (paddr & (nasys_icache_size - 1)) & (~(nasys_icache_line_size - 1)); + eset = (((paddr & (nasys_icache_size - 1)) + len) & (~(nasys_icache_line_size - 1))) + nasys_icache_line_size; + + __asm__ __volatile__ ( + "1:\n\t" + "flushi %0\n\t" + "add %0,%0,%2\n\t" + "blt %0,%1,1b\n\t" + "flushp\n\t" + : : "r" (sset), "r" (eset), "r" (nasys_icache_line_size)); + +} + +/* + * cache_push() semantics: Write back any dirty cache data in the given area, + * and invalidate the range in the instruction cache. It needs not (but may) + * invalidate those entries also in the data cache. The range is defined by a + * _physical_ address. + */ + +void cache_push (unsigned long paddr, int len) +{ + cache_invalidate_lines(paddr, len); +} + + +/* + * cache_push_v() semantics: Write back any dirty cache data in the given + * area, and invalidate those entries at least in the instruction cache. This + * is intended to be used after data has been written that can be executed as + * code later. The range is defined by a _user_mode_ _virtual_ address. + */ + +void cache_push_v (unsigned long vaddr, int len) +{ + cache_invalidate_lines(vaddr, len); +} + +/* + * cache_push_all() semantics: Invalidate instruction cache and write back + * dirty data cache & invalidate. + */ +void cache_push_all (void) +{ + __asm__ __volatile__ ( + "1:\n\t" + "flushd 0(%0)\n\t" + "sub %0,%0,%1\n\t" + "bgt %0,r0,1b\n\t" + : : "r" (nasys_dcache_size), "r" (nasys_dcache_line_size)); + + __asm__ __volatile__ ( + "1:\n\t" + "flushi %0\n\t" + "sub %0,%0,%1\n\t" + "bgt %0,r0,1b\n\t" + "flushp\n\t" + : : "r" (nasys_icache_size), "r" (nasys_icache_line_size)); + +} + +/* + * dcache_push() semantics: Write back and dirty data cache and invalidate + * the range. + */ +void dcache_push (unsigned long vaddr, int len) +{ + cache_invalidate_data(vaddr, len); +} + +/* + * icache_push() semantics: Invalidate instruction cache in the range. + */ +void icache_push (unsigned long vaddr, int len) +{ + cache_invalidate_inst(vaddr, len); +} + +/* Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ + +unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ) +{ + return paddr; +} + + +int is_in_rom(unsigned long addr) +{ + extern unsigned long _ramstart, _ramend; + + /* + * What we are really trying to do is determine if addr is + * in an allocated kernel memory region. If not then assume + * we cannot free it or otherwise de-allocate it. Ideally + * we could restrict this to really being in a ROM or flash, + * but that would need to be done on a board by board basis, + * not globally. + */ + if ((addr < _ramstart) || (addr >= _ramend)) + return(1); + + /* Default case, not in ROM */ + return(0); +} + +int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, int write_access) +{ + BUG(); + return VM_FAULT_OOM; +} diff --git a/arch/nios2nommu/scripts/PTF/PTFParser.pm b/arch/nios2nommu/scripts/PTF/PTFParser.pm new file mode 100644 index 00000000..c243c7b1 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/PTFParser.pm @@ -0,0 +1,873 @@ +#################################################################### +# +# This file was generated using Parse::Yapp version 1.05. +# +# Don't edit this file, use source file instead. +# +# ANY CHANGE MADE HERE WILL BE LOST ! +# +#################################################################### +package PTFParser; +use vars qw ( @ISA ); +use strict; + +@ISA= qw ( Parse::Yapp::Driver ); +#Included Parse/Yapp/Driver.pm file---------------------------------------- +{ +# +# Module Parse::Yapp::Driver +# +# This module is part of the Parse::Yapp package available on your +# nearest CPAN +# +# Any use of this module in a standalone parser make the included +# text under the same copyright as the Parse::Yapp module itself. +# +# This notice should remain unchanged. +# +# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved. +# (see the pod text in Parse::Yapp module for use and distribution rights) +# + +package Parse::Yapp::Driver; + +require 5.004; + +use strict; + +use vars qw ( $VERSION $COMPATIBLE $FILENAME ); + +$VERSION = '1.05'; +$COMPATIBLE = '0.07'; +$FILENAME=__FILE__; + +use Carp; + +#Known parameters, all starting with YY (leading YY will be discarded) +my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '', + YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => ''); +#Mandatory parameters +my(@params)=('LEX','RULES','STATES'); + +sub new { + my($class)=shift; + my($errst,$nberr,$token,$value,$check,$dotpos); + my($self)={ ERROR => \&_Error, + ERRST => \$errst, + NBERR => \$nberr, + TOKEN => \$token, + VALUE => \$value, + DOTPOS => \$dotpos, + STACK => [], + DEBUG => 0, + CHECK => \$check }; + + _CheckParams( [], \%params, \@_, $self ); + + exists($$self{VERSION}) + and $$self{VERSION} < $COMPATIBLE + and croak "Yapp driver version $VERSION ". + "incompatible with version $$self{VERSION}:\n". + "Please recompile parser module."; + + ref($class) + and $class=ref($class); + + bless($self,$class); +} + +sub YYParse { + my($self)=shift; + my($retval); + + _CheckParams( \@params, \%params, \@_, $self ); + + if($$self{DEBUG}) { + _DBLoad(); + $retval = eval '$self->_DBParse()';#Do not create stab entry on compile + $@ and die $@; + } + else { + $retval = $self->_Parse(); + } + $retval +} + +sub YYData { + my($self)=shift; + + exists($$self{USER}) + or $$self{USER}={}; + + $$self{USER}; + +} + +sub YYErrok { + my($self)=shift; + + ${$$self{ERRST}}=0; + undef; +} + +sub YYNberr { + my($self)=shift; + + ${$$self{NBERR}}; +} + +sub YYRecovering { + my($self)=shift; + + ${$$self{ERRST}} != 0; +} + +sub YYAbort { + my($self)=shift; + + ${$$self{CHECK}}='ABORT'; + undef; +} + +sub YYAccept { + my($self)=shift; + + ${$$self{CHECK}}='ACCEPT'; + undef; +} + +sub YYError { + my($self)=shift; + + ${$$self{CHECK}}='ERROR'; + undef; +} + +sub YYSemval { + my($self)=shift; + my($index)= $_[0] - ${$$self{DOTPOS}} - 1; + + $index < 0 + and -$index <= @{$$self{STACK}} + and return $$self{STACK}[$index][1]; + + undef; #Invalid index +} + +sub YYCurtok { + my($self)=shift; + + @_ + and ${$$self{TOKEN}}=$_[0]; + ${$$self{TOKEN}}; +} + +sub YYCurval { + my($self)=shift; + + @_ + and ${$$self{VALUE}}=$_[0]; + ${$$self{VALUE}}; +} + +sub YYExpect { + my($self)=shift; + + keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}} +} + +sub YYLexer { + my($self)=shift; + + $$self{LEX}; +} + + +################# +# Private stuff # +################# + + +sub _CheckParams { + my($mandatory,$checklist,$inarray,$outhash)=@_; + my($prm,$value); + my($prmlst)={}; + + while(($prm,$value)=splice(@$inarray,0,2)) { + $prm=uc($prm); + exists($$checklist{$prm}) + or croak("Unknow parameter '$prm'"); + ref($value) eq $$checklist{$prm} + or croak("Invalid value for parameter '$prm'"); + $prm=unpack('@2A*',$prm); + $$outhash{$prm}=$value; + } + for (@$mandatory) { + exists($$outhash{$_}) + or croak("Missing mandatory parameter '".lc($_)."'"); + } +} + +sub _Error { + print "Parse error.\n"; +} + +sub _DBLoad { + { + no strict 'refs'; + + exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ? + and return; + } + my($fname)=__FILE__; + my(@drv); + open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname"; + while() { + /^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/ + and do { + s/^#DBG>//; + push(@drv,$_); + } + } + close(DRV); + + $drv[0]=~s/_P/_DBP/; + eval join('',@drv); +} + +#Note that for loading debugging version of the driver, +#this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive. +#So, DO NOT remove comment at end of sub !!! +sub _Parse { + my($self)=shift; + + my($rules,$states,$lex,$error) + = @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' }; + my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos) + = @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' }; + +#DBG> my($debug)=$$self{DEBUG}; +#DBG> my($dbgerror)=0; + +#DBG> my($ShowCurToken) = sub { +#DBG> my($tok)='>'; +#DBG> for (split('',$$token)) { +#DBG> $tok.= (ord($_) < 32 or ord($_) > 126) +#DBG> ? sprintf('<%02X>',ord($_)) +#DBG> : $_; +#DBG> } +#DBG> $tok.='<'; +#DBG> }; + + $$errstatus=0; + $$nberror=0; + ($$token,$$value)=(undef,undef); + @$stack=( [ 0, undef ] ); + $$check=''; + + while(1) { + my($actions,$act,$stateno); + + $stateno=$$stack[-1][0]; + $actions=$$states[$stateno]; + +#DBG> print STDERR ('-' x 40),"\n"; +#DBG> $debug & 0x2 +#DBG> and print STDERR "In state $stateno:\n"; +#DBG> $debug & 0x08 +#DBG> and print STDERR "Stack:[". +#DBG> join(',',map { $$_[0] } @$stack). +#DBG> "]\n"; + + + if (exists($$actions{ACTIONS})) { + + defined($$token) + or do { + ($$token,$$value)=&$lex($self); +#DBG> $debug & 0x01 +#DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n"; + }; + + $act= exists($$actions{ACTIONS}{$$token}) + ? $$actions{ACTIONS}{$$token} + : exists($$actions{DEFAULT}) + ? $$actions{DEFAULT} + : undef; + } + else { + $act=$$actions{DEFAULT}; +#DBG> $debug & 0x01 +#DBG> and print STDERR "Don't need token.\n"; + } + + defined($act) + and do { + + $act > 0 + and do { #shift + +#DBG> $debug & 0x04 +#DBG> and print STDERR "Shift and go to state $act.\n"; + + $$errstatus + and do { + --$$errstatus; + +#DBG> $debug & 0x10 +#DBG> and $dbgerror +#DBG> and $$errstatus == 0 +#DBG> and do { +#DBG> print STDERR "**End of Error recovery.\n"; +#DBG> $dbgerror=0; +#DBG> }; + }; + + + push(@$stack,[ $act, $$value ]); + + $$token ne '' #Don't eat the eof + and $$token=$$value=undef; + next; + }; + + #reduce + my($lhs,$len,$code,@sempar,$semval); + ($lhs,$len,$code)=@{$$rules[-$act]}; + +#DBG> $debug & 0x04 +#DBG> and $act +#DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): "; + + $act + or $self->YYAccept(); + + $$dotpos=$len; + + unpack('A1',$lhs) eq '@' #In line rule + and do { + $lhs =~ /^\@[0-9]+\-([0-9]+)$/ + or die "In line rule name '$lhs' ill formed: ". + "report it as a BUG.\n"; + $$dotpos = $1; + }; + + @sempar = $$dotpos + ? map { $$_[1] } @$stack[ -$$dotpos .. -1 ] + : (); + + $semval = $code ? &$code( $self, @sempar ) + : @sempar ? $sempar[0] : undef; + + splice(@$stack,-$len,$len); + + $$check eq 'ACCEPT' + and do { + +#DBG> $debug & 0x04 +#DBG> and print STDERR "Accept.\n"; + + return($semval); + }; + + $$check eq 'ABORT' + and do { + +#DBG> $debug & 0x04 +#DBG> and print STDERR "Abort.\n"; + + return(undef); + + }; + +#DBG> $debug & 0x04 +#DBG> and print STDERR "Back to state $$stack[-1][0], then "; + + $$check eq 'ERROR' + or do { +#DBG> $debug & 0x04 +#DBG> and print STDERR +#DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n"; + +#DBG> $debug & 0x10 +#DBG> and $dbgerror +#DBG> and $$errstatus == 0 +#DBG> and do { +#DBG> print STDERR "**End of Error recovery.\n"; +#DBG> $dbgerror=0; +#DBG> }; + + push(@$stack, + [ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]); + $$check=''; + next; + }; + +#DBG> $debug & 0x04 +#DBG> and print STDERR "Forced Error recovery.\n"; + + $$check=''; + + }; + + #Error + $$errstatus + or do { + + $$errstatus = 1; + &$error($self); + $$errstatus # if 0, then YYErrok has been called + or next; # so continue parsing + +#DBG> $debug & 0x10 +#DBG> and do { +#DBG> print STDERR "**Entering Error recovery.\n"; +#DBG> ++$dbgerror; +#DBG> }; + + ++$$nberror; + + }; + + $$errstatus == 3 #The next token is not valid: discard it + and do { + $$token eq '' # End of input: no hope + and do { +#DBG> $debug & 0x10 +#DBG> and print STDERR "**At eof: aborting.\n"; + return(undef); + }; + +#DBG> $debug & 0x10 +#DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n"; + + $$token=$$value=undef; + }; + + $$errstatus=3; + + while( @$stack + and ( not exists($$states[$$stack[-1][0]]{ACTIONS}) + or not exists($$states[$$stack[-1][0]]{ACTIONS}{error}) + or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) { + +#DBG> $debug & 0x10 +#DBG> and print STDERR "**Pop state $$stack[-1][0].\n"; + + pop(@$stack); + } + + @$stack + or do { + +#DBG> $debug & 0x10 +#DBG> and print STDERR "**No state left on stack: aborting.\n"; + + return(undef); + }; + + #shift the error token + +#DBG> $debug & 0x10 +#DBG> and print STDERR "**Shift \$error token and go to state ". +#DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}. +#DBG> ".\n"; + + push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]); + + } + + #never reached + croak("Error in driver logic. Please, report it as a BUG"); + +}#_Parse +#DO NOT remove comment + +1; + +} +#End of include-------------------------------------------------- + + +#line 1 "PTFParser.yp" +# +# Altera PTF file parser +# +# Copyright (c) 2004 Microtronix Datacom Ltd. +# + +package PTFParser; + +use PTF::PTFSection; + +#global variables should go here. + +#my $line = 0; # for error messages +#my @sectionStack = (); # used to keep track of ptf sections +#my $root; + +my $fh; + +sub new { + my($class)=shift; + ref($class) + and $class=ref($class); + + my($self)=$class->SUPER::new( yyversion => '1.05', + yystates => +[ + {#State 0 + ACTIONS => { + 'IDENTIFIER' => 1 + }, + GOTOS => { + 'section' => 2, + 'section_title' => 3 + } + }, + {#State 1 + ACTIONS => { + 'IDENTIFIER' => 4, + 'STRING_LITERAL' => 6, + 'NUMBER' => 7 + }, + DEFAULT => -3, + GOTOS => { + 'section_name' => 5 + } + }, + {#State 2 + ACTIONS => { + '' => 8 + } + }, + {#State 3 + ACTIONS => { + "{" => 9 + } + }, + {#State 4 + DEFAULT => -4 + }, + {#State 5 + DEFAULT => -2 + }, + {#State 6 + DEFAULT => -6 + }, + {#State 7 + DEFAULT => -5 + }, + {#State 8 + DEFAULT => 0 + }, + {#State 9 + ACTIONS => { + 'IDENTIFIER' => 11, + 'HIERARCHICAL_NAME' => 13 + }, + DEFAULT => -7, + GOTOS => { + 'assignment_name' => 10, + 'assignment' => 12, + 'section_element' => 14, + 'section' => 15, + 'section_title' => 3 + } + }, + {#State 10 + ACTIONS => { + "=" => 16 + } + }, + {#State 11 + ACTIONS => { + 'IDENTIFIER' => 4, + 'STRING_LITERAL' => 6, + 'NUMBER' => 7, + "=" => -11 + }, + DEFAULT => -3, + GOTOS => { + 'section_name' => 5 + } + }, + {#State 12 + ACTIONS => { + 'IDENTIFIER' => 11, + 'HIERARCHICAL_NAME' => 13 + }, + DEFAULT => -7, + GOTOS => { + 'assignment_name' => 10, + 'assignment' => 12, + 'section_element' => 17, + 'section' => 15, + 'section_title' => 3 + } + }, + {#State 13 + DEFAULT => -12 + }, + {#State 14 + ACTIONS => { + "}" => 18 + } + }, + {#State 15 + ACTIONS => { + 'IDENTIFIER' => 11, + 'HIERARCHICAL_NAME' => 13 + }, + DEFAULT => -7, + GOTOS => { + 'assignment_name' => 10, + 'assignment' => 12, + 'section_element' => 19, + 'section' => 15, + 'section_title' => 3 + } + }, + {#State 16 + ACTIONS => { + 'STRING_LITERAL' => 20, + 'NUMBER' => 22 + }, + GOTOS => { + 'assignment_value' => 21 + } + }, + {#State 17 + DEFAULT => -8 + }, + {#State 18 + DEFAULT => -1 + }, + {#State 19 + DEFAULT => -9 + }, + {#State 20 + DEFAULT => -13 + }, + {#State 21 + ACTIONS => { + ";" => 23 + } + }, + {#State 22 + DEFAULT => -14 + }, + {#State 23 + DEFAULT => -10 + } +], + yyrules => +[ + [#Rule 0 + '$start', 2, undef + ], + [#Rule 1 + 'section', 4, +sub +#line 20 "PTFParser.yp" +{ + my $sectionStack = $_[0]->YYData->{sectionStack}; + pop @{$sectionStack}; + } + ], + [#Rule 2 + 'section_title', 2, +sub +#line 26 "PTFParser.yp" +{ + my $section = PTFSection->new (type => $_[1], name => $_[2]); + my $sectionStack = $_[0]->YYData->{sectionStack}; + + if (scalar(@{$sectionStack}) == 0) { + $_[0]->YYData->{root} = $section; + } else { + my $parent = $sectionStack->[$#{$sectionStack}]; + $parent->addSection ($section); + } + + push @{$sectionStack}, $section; + } + ], + [#Rule 3 + 'section_name', 0, undef + ], + [#Rule 4 + 'section_name', 1, undef + ], + [#Rule 5 + 'section_name', 1, undef + ], + [#Rule 6 + 'section_name', 1, undef + ], + [#Rule 7 + 'section_element', 0, undef + ], + [#Rule 8 + 'section_element', 2, undef + ], + [#Rule 9 + 'section_element', 2, undef + ], + [#Rule 10 + 'assignment', 4, +sub +#line 52 "PTFParser.yp" +{ + my $sectionStack = $_[0]->YYData->{sectionStack}; + my $parent= $sectionStack->[$#{$sectionStack}]; + $parent->addAssignment ($_[1], $_[3]); + } + ], + [#Rule 11 + 'assignment_name', 1, undef + ], + [#Rule 12 + 'assignment_name', 1, undef + ], + [#Rule 13 + 'assignment_value', 1, undef + ], + [#Rule 14 + 'assignment_value', 1, undef + ] +], + @_); + bless($self,$class); +} + +#line 67 "PTFParser.yp" + + +sub _Error { +# TODO: update this error function to be more useful + exists $_[0]->YYData->{ERRMSG} + and do { + print $_[0]->YYData->{ERRMSG}; + delete $_[0]->YYData->{ERRMSG}; + return; + }; + print "Syntax error on line $_[0]->YYData->{line}.\n"; +} + +sub _Lexer { + my($parser)=shift; + + if (! $parser->YYData->{INPUT}) { + if ($parser->YYData->{INPUT} = <$fh>) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + } + + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + + while (1) { + + # skip blank lines + if ($parser->YYData->{INPUT} =~ s/^[ \t\r\n]*$//) { + if ($parser->YYData->{INPUT} = <$fh>) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # Skip comments + if ($parser->YYData->{INPUT} =~ s/^#.*//) { + if ($parser->YYData->{INPUT} = <$fh>) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # Don't continue if the line length is 0; + if (length $parser->YYData->{INPUT} == 0) { + if ($parser->YYData->{INPUT} = <$fh>) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # tokenize input + $parser->YYData->{INPUT} =~ s/^([a-zA-Z_][a-zA-Z_0-9\/]*)// + and return('IDENTIFIER',$1); + $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)"// + and return('STRING_LITERAL',$1); + $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)// + and do { + my $literal = $1; + + do { + if ($parser->YYData->{INPUT} = <$fh>) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + + $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)"// + and do { + $literal .= $1; + return ('STRING_LITERAL', $literal); + }; + + $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)// + and $literal .= $1; + } while (1); + }; + $parser->YYData->{INPUT} =~ s/^([0-9]+)// + and return('NUMBER',$1); + $parser->YYData->{INPUT} =~ s/^([\$]{1,2}[a-zA-Z0-9 \/_]+)// + and return('HIERARCHICAL_NAME',$1); + $parser->YYData->{INPUT} =~ s/^(.)// + and return($1,$1); + } +} + +sub readPTF { + my $self = shift; + my $filename = shift; + + # store information for later use + $self->YYData->{line} = 0; + $self->YYData->{sectionStack} = []; + undef $self->YYData->{root}; + + if (-e $filename) { + open (PTFFILE, $filename); + $fh = \*PTFFILE; + } else { + $fh = \*STDIN; + } + + $self->YYParse ( + yylex => \&_Lexer, + yyerror => \&_Error, + ); + + if (-e $filename) { + close PTFFILE; + } + + return $self->YYData->{root}; +} + +1; diff --git a/arch/nios2nommu/scripts/PTF/PTFParser.yp b/arch/nios2nommu/scripts/PTF/PTFParser.yp new file mode 100644 index 00000000..e105e6a2 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/PTFParser.yp @@ -0,0 +1,178 @@ +%{# +# Altera PTF file parser +# +# Copyright (c) 2004 Microtronix Datacom Ltd. +# + +package PTFParser; + +use PTF::PTFSection; + +%} + +%% +section: section_title '{' section_element '}' { + my $sectionStack = $_[0]->YYData->{sectionStack}; + pop @{$sectionStack}; + } +; + +section_title: IDENTIFIER section_name { + my $section = PTFSection->new (type => $_[1], name => $_[2]); + my $sectionStack = $_[0]->YYData->{sectionStack}; + + if (scalar(@{$sectionStack}) == 0) { + $_[0]->YYData->{root} = $section; + } else { + my $parent = $sectionStack->[$#{$sectionStack}]; + $parent->addSection ($section); + } + + push @{$sectionStack}, $section; + } +; + +section_name: # empty string + | IDENTIFIER + | NUMBER + | STRING_LITERAL +; + +section_element: # empty element + | assignment section_element + | section section_element +; + +assignment: assignment_name '=' assignment_value ';' { + my $sectionStack = $_[0]->YYData->{sectionStack}; + my $parent= $sectionStack->[$#{$sectionStack}]; + $parent->addAssignment ($_[1], $_[3]); + } +; + +assignment_name: IDENTIFIER + | HIERARCHICAL_NAME +; + +assignment_value: STRING_LITERAL + | NUMBER +; + +%% + +sub _Error { +# TODO: update this error function to be more useful + exists $_[0]->YYData->{ERRMSG} + and do { + print $_[0]->YYData->{ERRMSG}; + delete $_[0]->YYData->{ERRMSG}; + return; + }; + print "Syntax error on line $_[0]->YYData->{line}.\n"; +} + +sub _Lexer { + my($parser)=shift; + + if (! $parser->YYData->{INPUT}) { + if ($parser->YYData->{INPUT} = ) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + } + + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + + while (1) { + + # skip blank lines + if ($parser->YYData->{INPUT} =~ s/^[ \t\r\n]*$//) { + if ($parser->YYData->{INPUT} = ) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # Skip comments + if ($parser->YYData->{INPUT} =~ s/^#.*//) { + if ($parser->YYData->{INPUT} = ) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # Don't continue if the line length is 0; + if (length $parser->YYData->{INPUT} == 0) { + if ($parser->YYData->{INPUT} = ) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + $parser->YYData->{INPUT} and + $parser->YYData->{INPUT} =~ s/^\s*//; + next; + } + + # tokenize input + $parser->YYData->{INPUT} =~ s/^([a-zA-Z_][a-zA-Z_0-9\/]*)// + and return('IDENTIFIER',$1); + $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)"// + and return('STRING_LITERAL',$1); + $parser->YYData->{INPUT} =~ s/^"([^"\\]*(\\.[^"\\]*)*)// + and do { + my $literal = $1; + + do { + if ($parser->YYData->{INPUT} = ) { + $parser->YYData->{line} += 1; + } else { + return ('', undef); + } + + $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)"// + and do { + $literal .= $1; + return ('STRING_LITERAL', $literal); + }; + + $parser->YYData->{INPUT} =~ s/([^"\\]*(\\.[^"\\]*)*)// + and $literal .= $1; + } while (1); + }; + $parser->YYData->{INPUT} =~ s/^([0-9]+)// + and return('NUMBER',$1); + $parser->YYData->{INPUT} =~ s/^([\$]{1,2}[a-zA-Z0-9 \/_]+)// + and return('HIERARCHICAL_NAME',$1); + $parser->YYData->{INPUT} =~ s/^(.)// + and return($1,$1); + } +} + +sub readPTF { + my $self = shift; + my $filename = shift; + + # store information for later use + $self->YYData->{line} = 0; + $self->YYData->{sectionStack} = []; + undef $self->YYData->{root}; + + open (PTFFILE, $filename) or return undef; + $self->YYParse ( + yylex => \&_Lexer, + yyerror => \&_Error, + ); + close PTFFILE; + + return $self->YYData->{root}; +} diff --git a/arch/nios2nommu/scripts/PTF/PTFSection.pm b/arch/nios2nommu/scripts/PTF/PTFSection.pm new file mode 100644 index 00000000..a88d3405 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/PTFSection.pm @@ -0,0 +1,81 @@ +package PTFSection; + +use strict; + +# Fields: +# type = type of PTF Section +# name = name of PTF Section (can be blank) +# sections = array of section references +# assignments = hash of assignments + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = { + @_, + sections => [], + assignments => {}, + }; + bless ($self, $class); + return $self; +} + +sub addSection { + my ($self, $section) = @_; + push @{$self->{sections}}, $section; +} + +sub getSections { + my ($self, $type) = @_; + + if (! $type) { + return @{$self->{sections}}; + } + + my @matchedSections; + foreach my $section (@{$self->{sections}}) { + if ($section->type eq $type) { + push @matchedSections, $section; + } + } + + return @matchedSections; +} + +sub getSection { + my ($self, $type, $name) = @_; + + if (! $name) { + $name = ""; + } + + foreach my $section (@{$self->{sections}}) { + if ($section->type eq $type and $section->name eq $name) { + return $section; + } + } + +} + +sub addAssignment { + my ($self, $name, $value) = @_; + $self->{assignments}{$name} = $value; +} + +sub getAssignment { + my ($self, $name) = @_; + return $self->{assignments}{$name}; +} + +sub type { + my $self = shift; + return $self->{type}; +} + +sub name { + my $self = shift; + return $self->{name}; +} + + +1; diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF.pm b/arch/nios2nommu/scripts/PTF/SystemPTF.pm new file mode 100644 index 00000000..9f44cfe3 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/SystemPTF.pm @@ -0,0 +1,149 @@ +package SystemPTF; + +use strict; + +use PTF::PTFParser; +use PTF::PTFSection; +use PTF::SystemPTF::CPU; +use PTF::SystemPTF::Board; +use PTF::SystemPTF::Module; + +# Fields: + +my %module_order; + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = { + filename => "", + @_, + }; + + my $parser = PTFParser->new; + $self->{root} = $parser->readPTF($self->{filename}); + + # if the specified PTF file could not be read properly, return undef; + $self->{root} or return; + + # if the specified PTF file is not a SYSTEM, return undef. + if ($self->{root}->type ne 'SYSTEM') { + return; + } + + # initialize the modulemap + my @modules = $self->{root}->getSections ("MODULE"); + my $index = 0; + foreach my $module (@modules) { + # if the module is not enabled then do not add + my $SBI = $module->getSection ('SYSTEM_BUILDER_INFO', ''); + if ($SBI->getAssignment ('Is_Enabled') eq "1") { + $self->{modules}->{$module->name} = $module; + $module_order{$module->name} = $index; + $index += 1; + } + } + + bless ($self, $class); + return $self; +} + +sub getName { + my ($self) = @_; + return $self->{root}->name; +} + +sub getCPUList { + my ($self, @classes) = @_; + my @cpulist = (); + + foreach my $module_name (keys (%{$self->{modules}})) { + my $module = $self->{modules}->{$module_name}; + my $module_class = $module->getAssignment ('class'); + foreach my $class (@classes) { + if ($module_class eq $class) { + push @cpulist, $module->name; + } + } + } + + return @cpulist; +} + +sub getCPU { + my ($self, $name) = @_; + + my $cpu = CPU->new (ptf => $self->{modules}->{$name}); +} + +sub getModule { + my ($self, $name) = @_; + + my $module = Module->new (ptf => $self->{modules}->{$name}); +} + +sub getSlaveModules { + my ($self, $master, $type) = @_; + + # create %connected set with just the master + # value of hash key is inconsequential + my %connected; + $connected{$master} = ( ); + + # create %pool set with all modules + # value of hash key is inconsequential + my %pool; + @pool{keys (%{$self->{modules}})} = ( ); + + my $dirty = 1; + while ($dirty) { + # %pool = difference (%pool, %connected) + delete @pool{ keys %connected }; + + $dirty = 0; + + foreach my $name (keys %pool) { + my $mod = $self->getModule ($name); + my %mod_masters; + @mod_masters{ $mod->getMasters ($type) } = ( ); + + # if intersection (%masters, %connected) is not empty + delete @mod_masters{ + grep ( ! exists $connected{ $_ }, + keys %mod_masters) }; + + if (scalar(keys(%mod_masters)) > 0) { + $connected{$name} = ( ); + $dirty = 1; + } + } + } + + delete $connected{$master}; + + return sort module_comparison keys (%connected); +} + +sub getClockFreq () { + my ($self) = @_; + + my $wsa = $self->{root}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); + $wsa or return; + + my $result = $wsa->getAssignment ('clock_freq'); + return $result; +} + +# This is not really a class method... more of a helper function really... +sub module_comparison { + if ($module_order{$a} > $module_order{$b}) { + return 1; + } elsif ($module_order{$a} < $module_order{$b}) { + return -1; + } else { + return 0; + } +} + + +1; diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm new file mode 100644 index 00000000..fe2bbc8d --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/SystemPTF/Board.pm @@ -0,0 +1,2 @@ +1; + diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm new file mode 100644 index 00000000..ea105986 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/SystemPTF/CPU.pm @@ -0,0 +1,89 @@ +package CPU; + +use PTF::PTFSection; + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = { + @_, + }; + + # if no ptf section was passed in, then return undef + $self->{ptf} or return; + + bless ($self, $class); + return $self; +} + +sub getClass { + my ($self) = @_; + + return $self->{ptf}->getAssignment ('class'); +} + +sub getVersion { + my ($self) = @_; + + return $self->{ptf}->getAssignment ('class_version'); +} + +sub getConstant { + my ($self, $name) = @_; + + # get WSA + $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); + $wsa or return; + + # get constants section + $constants = $wsa->getSection('CONSTANTS', ''); + $constants or return; + + # get section for specific constant + $constant = $constants->getSection ('CONSTANT', $name); + $constant or return; + + # get value of constant + $value = $constant->getAssignment ('value'); + return $value; +} + +sub getWSAAssignment { + my ($self, $name) = @_; + + # get WSA + $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); + $wsa or return; + + # get value of WSA Assignment + $value = $wsa->getAssignment ($name); + return $value; +} + +sub getResetLocationOffset { + my ($self) = @_; + + $wsa = $self->{ptf}->getSection('WIZARD_SCRIPT_ARGUMENTS', ''); + $wsa or return; + + my $location = $wsa->getAssignment ('reset_slave'); + my $offset = $wsa->getAssignment ('reset_offset'); + + return ($location, $offset); +} + +sub isEnabled { + my ($self) = @_; + + $sbi = $self->{ptf}->getSection('SYSTEM_BUILDER_INFO', ''); + $sbi or return; + + my $enabled = $sbi->getAssignment ('Is_Enabled'); + if ($enabled eq "1") { + return 1; + } else { + return 0; + } +} + +1; diff --git a/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm b/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm new file mode 100644 index 00000000..48d246b2 --- /dev/null +++ b/arch/nios2nommu/scripts/PTF/SystemPTF/Module.pm @@ -0,0 +1,267 @@ +package Module; + +use PTF::PTFSection; + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = { + @_, + }; + + # if no ptf section was passed in, then return undef + $self->{ptf} or return; + + bless ($self, $class); + return $self; +} + +sub getClass { + my ($self) = @_; + + return $self->{ptf}->getAssignment ('class'); +} + +sub getPorts { + my ($self) = @_; + + my @port_names; + + my @ports = $self->{ptf}->getSections ('SLAVE'); + foreach $port (@ports) { + push @port_names, $port->name; + } + + return @port_names; +} + +sub getPort { + my ($self, $port_name) = @_; + + my $port; + + if (! $port_name) { + # use first port found + my @port_names = $self->getPorts (); + $port = $self->{ptf}->getSection ('SLAVE', $port_names[0]); + } else { + $port = $self->{ptf}->getSection ('SLAVE', $port_name); + if (! $port) { + # return undef if the PTF section doesn't exist + return; + } + } + + return $port; +} + +sub getWSAAssignment { + my ($self, $assignment) = @_; + + my $WSA = $self->{ptf}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); + if (! $WSA) { + # return undef if the WSA section doesn't exist. + return; + } + + my $result = $WSA->getAssignment ($assignment); + + return $result; + +} + +sub getWSAConstant { + my ($self, $name) = @_; + + my $WSA = $self->{ptf}->getSection ('WIZARD_SCRIPT_ARGUMENTS', ''); + if (! $WSA) { + # return undef if the WSA section doesn't exist. + return; + } + + my $constants = $WSA->getSection ('CONSTANTS', ''); + if (! $constants) { + # return undef if the CONSTANTS section doesn't exist. + return; + } + + my $constant = $constants->getSection ('CONSTANT', $name); + if (! $constant) { + # return undef if the CONSTANT $name section doesn't exist. + return; + } + + my $result = $constant->getAssignment ('value'); + return $result; + +} + +sub isMemoryDevice { + my ($self, $port_name) = @_; + + my $port = $self->getPort ($port_name); + if (! $port) { + # return undef if the PTF section doesn't exist + return; + } + + my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); + if (! $SBI) { + # return undef if the PTF section doesn't exist + return; + } + + my $result = $SBI->getAssignment('Is_Memory_Device'); + + return $result; +} + +sub isCustomInstruction { + my ($self, $port_name) = @_; + + my $port = $self->getPort ($port_name); + if (! $port) { + # return undef if the PTF section doesn't exist + return; + } + + my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); + if (! $SBI) { + # return undef if the PTF section doesn't exist + return; + } + + my $result = $SBI->getAssignment('Is_Custom_Instruction'); + + return $result; +} + +sub getBaseAddress { + my ($self, $port_name) = @_; + + my $port = $self->getPort ($port_name); + if (! $port) { + # return undef if the PTF section doesn't exist + return; + } + + my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); + if (! $SBI) { + # return undef if the PTF section doesn't exist + return; + } + + my $result = $SBI->getAssignment('Base_Address'); + if ($result eq 'N/A') { + return; + } + return $result; +} + +sub getSize { + my ($self, $port_name) = @_; + + my $port = $self->getPort ($port_name); + $port or return; #return undef if the ptf section doesn't exist + + my $SBI = $port->getSection ('SYSTEM_BUILDER_INFO', ''); + my $data_width = $SBI->getAssignment ('Data_Width'); + my $addr_width = $SBI->getAssignment ('Address_Width'); + + if ($data_width == 8) { + $size = 1 << $addr_width; + } elsif ($data_width == 16) { + $size = 1 << ($addr_width + 1); + } elsif ($data_width == 32) { + $size = 1 << ($addr_width + 2); + } elsif ($data_width == 64) { + $size = 1 << ($addr_width + 3); + } elsif ($data_width == 128) { + $size = 1 << ($addr_width + 4); + } else { + return; + } + + $size_text = sprintf ("%#010x", $size); + return $size_text; +} + +sub getIRQ { + my ($self, $port_name) = @_; + + my $port = $self->getPort ($port_name); + if (! $port) { + # return undef if the PTF section doesn't exist + return; + } + + my $SBI = $port->getSection('SYSTEM_BUILDER_INFO', ''); + if (! $SBI) { + # return undef if the PTF section doesn't exist + return; + } + + my $result = $SBI->getAssignment('Has_IRQ'); + if ($result ne "1") { + # this device has no associated IRQ + return; + } + + my @irq_masters = $SBI->getSections('IRQ_MASTER'); + return $irq_masters[0]->getAssignment('IRQ_Number'); +} + +sub getMasters { + my ($self, $type) = @_; + my %masters = (); + + # get list of all slave for device + my @slaves = $self->{ptf}->getSections ('SLAVE'); + + # get list of masters of relevant type for all slaves + foreach my $slave (@slaves) { + # get SBI for slave + my $SBI = $slave->getSection ('SYSTEM_BUILDER_INFO', ''); + + # get list of all MASTERED_BY and IRQ_MASTER sections + my @mastered_bys = $SBI->getSections ('MASTERED_BY'); + my @irq_masters = $SBI->getSections ('IRQ_MASTER'); + + # start adding masters to the list + foreach my $master (@mastered_bys, @irq_masters) { + my $section_name = $master->name; + $section_name =~ /(.*)\/(.*)/; + my $master_name = $1; + my $master_type = $2; + + if (! $type) { + $masters{$master_name} = (); + } else { + if ($master_type eq $type) { + $masters{$master_name} = (); + } + } + + } + + } + + return keys (%masters); +} + +sub isEnabled { + my ($self) = @_; + + $sbi = $self->{ptf}->getSection('SYSTEM_BUILDER_INFO', ''); + $sbi or return; + + my $enabled = $sbi->getAssignment ('Is_Enabled'); + if ($enabled eq "1") { + return 1; + } else { + return 0; + } +} + +1; + diff --git a/arch/nios2nommu/scripts/gen_nios2_system.h.pl b/arch/nios2nommu/scripts/gen_nios2_system.h.pl new file mode 100644 index 00000000..b7bcff58 --- /dev/null +++ b/arch/nios2nommu/scripts/gen_nios2_system.h.pl @@ -0,0 +1,314 @@ +# This script generates an appropriate hardware.h file for Nios II Linux based +# on information within the target hardware's system.ptf file. This script +# outputs everything to stdout. +# +# usage: +# +# [SOPC Builder]$ perl gen_hardware.h.pl \ +# +# + +use PTF::SystemPTF; +use strict; +use integer; + +my $target_cpu; +my $exec_location; +my $upload_location; + +if (scalar (@ARGV) != 3) { + print STDERR "ERROR: Invalid number of parameters.\n"; + print ("#error Invalid number of parameters.\n"); + exit; +} else { + $target_cpu = $ARGV[0]; + $exec_location = $ARGV[1]; + $upload_location = $ARGV[2]; +} + +# +# startup the parser. +# +my $system = SystemPTF->new; +if (!$system) { + print STDERR "ERROR: Specified file is not a SYSTEM ptf file.\n"; + print ("#error Specified file is not a SYSTEM ptf file.\n"); + exit; +} + +# +# print header for nios2_system.h +# +print <getCPU ($target_cpu); +if (! $cpu) { + print STDERR "ERROR: $target_cpu is not a valid CPU in system: " . $system->getName () . ".\n"; + print "#error $target_cpu is not a valid CPU in system: " . $system->getName () . ".\n"; + exit 1; +} + +my $exec_module = $system->getModule ($exec_location); +if (! $exec_module) { + print STDERR "ERROR: $exec_location is not a valid module in the system: " . $system->getName() . ".\n"; + print "#error $exec_location is not a valid module in system: " . $system->getName () . ".\n"; + exit 1; +} + +my $upload_module = $system->getModule ($upload_location); +if (! $upload_module) { + print STDERR "ERROR: $upload_location is not a valid module in the system: " . $system->getName() . ".\n"; + print "#error $upload_location is not a valid module in system: " . $system->getName () . ".\n"; + exit 1; +} + +my %found_classes; +my @found_classes_order; + +# the SYSPTF environment variable is set by kernel build process. +if ($ENV{SYSPTF} ne "") { + print "/* Input System: " . $ENV{SYSPTF} . ":" . $system->getName () . " */\n"; +} else { + print "/* Input System: " . $system->getName () . " */\n"; +} +print "/* Target CPU: " . $target_cpu . " */\n"; + +print "\n"; + +print <getSlaveModules ($target_cpu); +foreach my $module_name (@module_names) { + my $module = $system->getModule ($module_name); + my $module_class = $module->getClass (); + my @module_ports = $module->getPorts (); + my $mask = 0; + my $text_printed = 0; + my $output = ""; + + # $output .= "/* $module_name (of type $module_class) */\n"; + + if (! exists $found_classes{$module_class}) { + push @found_classes_order, $module_class; + } + push @{$found_classes{$module_class}}, $module_name; + + if (! $module->isMemoryDevice () && ! $module->isCustomInstruction ()) { + # turn on high bit for base address + $mask = 0x80000000; + } + + if (scalar (@module_ports) == 1) { + my $base_address; + my $mem_size; + my $mem_end; + + # base address information + $base_address = $module->getBaseAddress (); + if ($base_address) { + $output .= sprintf ("#define na_%-50s %#010x\n", + ($module_name, hex ($base_address) | $mask)); + $text_printed = 1; + } + if ($module->isMemoryDevice()) { + # output size and end address + $mem_size = $module->getSize(); + $output .= sprintf ("#define na_%-50s %#010x\n", + ($module_name . "_size", hex ($mem_size))); + $mem_end = hex ($mem_size) + hex($base_address); + $output .= sprintf ("#define na_%-50s %#010x\n", + ($module_name . "_end", $mem_end)); + + $text_printed = 1; + } + + # irq information + $result = $module->getIRQ (); + if (defined ($result)) { + $output .= sprintf ("#define na_%-30s %30s\n", + ($module_name . "_irq", $result)); + $text_printed = 1; + } + + } else { + # if device has multiple ports + foreach my $port_name (@module_ports) { + # base address information + $result = $module->getBaseAddress ($port_name); + if ($result) { + $output .= sprintf ("#define na_%-50s %#010x\n", + ($module_name . "_" . $port_name, hex ($result) | $mask)); + $text_printed = 1; + } + + # irq information + $result = $module->getIRQ ($port_name); + if (defined ($result)) { + $output .= sprintf ("#define na_%-30s %30s\n", + ($module_name . "_" . $port_name . "_irq", $result)); + $text_printed = 1; + } + } + } + + if ($text_printed == 1) { + # $output .= "\n"; + print $output; + } +} + +print "\n"; + +# +# Handle special cases through customized perl scripts +# +foreach my $class_name (@found_classes_order) { + my $code = ""; + + foreach my $dir (@INC) { + if (-e "$dir/nios2_system.h/$class_name.pm") { + print "/* Executing ...scripts/nios2_system.h/$class_name.pm */\n"; + $code .= "require \"$dir/nios2_system.h/BasicModule.pm\";"; + $code .= "require \"$dir/nios2_system.h/$class_name.pm\";"; + $code .= $class_name . "::run(\$system, \@{\$found_classes{\$class_name}});"; + eval $code; + if ($@) { + print "#warning Could not execute ...scripts/nios2_system.h/$class_name.pm\n"; + print "#warning Error message is stored in nios2_system.h:\n"; + print "/*\n"; + print "$@"; + print "*/\n"; + print STDERR "Could not execute ...scripts/nios2_system.h/$class_name.pm\n"; + print STDERR "Error message follows:\n"; + print STDERR "$@"; + } + last; + } + } +} + +# +# Write out system information +# +print "/*\n"; +print " * Basic System Information\n"; +print " */\n"; + +$result = $cpu->getWSAAssignment ('cache_icache_size'); +printf ("#define %-53s %10d\n", ("nasys_icache_size", $result)); + +$result = $cpu->getConstant ('nasys_icache_line_size'); +printf ("#define %-53s %10d\n", ("nasys_icache_line_size", $result)); + +$result = $cpu->getWSAAssignment ('cache_dcache_size'); +printf ("#define %-53s %10d\n", ("nasys_dcache_size", $result)); + +$result = $cpu->getConstant ('nasys_dcache_line_size'); +printf ("#define %-53s %10d\n", ("nasys_dcache_line_size", $result)); + +print "\n"; + +printf ("#define %-33s %30s\n", + ("nasys_program_mem", "na_${exec_location}")); +printf ("#define %-33s %30s\n", + ("nasys_program_mem_size", "na_${exec_location}_size")); +printf ("#define %-33s %30s\n", + ("nasys_program_mem_end", "na_${exec_location}_end")); + +print "\n"; + +if ($upload_location eq "flash_kernel") { + # nothing to do + print ("/* Redefinition of CFI flash memory unecessary */\n"); +} else { + my $module = $system->getModule ("flash_kernel"); + if ($module) { + # there is a conflicting module in the system, error. + print STDERR "Error, a SOPC module named flash_kernel already exists but is not the upload location.\n"; + print "#error The module name \"flash_kernel\" already exists but isn't the upload location.\n"; + print "#error This will break the kernel.\n"; + print "#error Please rename the module to something else in SOPC Builder.\n\n"; + exit 1; + } else { + print ("/*\n"); + print (" * Redefining upload location ($upload_location) to flash_kernel.\n"); + print (" */\n\n"); + # undefine the original module names and re-define them here. + print ("#undef na_${upload_location}\n"); + print ("#undef na_${upload_location}_size\n"); + print ("#undef na_${upload_location}_end\n"); + + my $base_address = $upload_module->getBaseAddress (); + printf ("#define %-33s %30s\n", + ("na_flash_kernel", $base_address)); + + my $mem_size = $upload_module->getSize(); + printf ("#define %-33s %30s\n", + ("na_flash_kernel_size", $mem_size)); + + my $mem_end = hex ($base_address) + hex ($mem_size); + printf ("#define %-53s %#010x\n", + ("na_flash_kernel_end", $mem_end)); + } +} + +print "\n"; + +printf ("#define %-33s %30s\n", + ("nasys_clock_freq", $system->getClockFreq())); +printf ("#define %-33s %30s\n", + ("nasys_clock_freq_1000", int ($system->getClockFreq()) / 1000)); + +{ + my ($reset_location, $reset_offset) = $cpu->getResetLocationOffset(); + my ($reset_module_name, $reset_port_name) = ($reset_location =~ /(.*)\/(.*)/); + my $reset_module = $system->getModule ($reset_module_name); + my $reset_address = $reset_module->getBaseAddress ($reset_port_name); + + $reset_address = hex ($reset_address) + hex ($reset_offset); + printf ("#define %-53s %#010x\n", + ("CPU_RESET_ADDRESS", $reset_address)); +} + +print "\n"; + +# +# print footer for nios2_system.h +# +print < +# + +use PTF::SystemPTF; +use strict; +use integer; + +my $ptf_filename; +my $target_filename; +my $index; +my $system; + +# +# Subroutine: Prompt user for an answer +# + +sub request_answer { + my ($min, $max) = @_; + my $answer; + + do { + print "Selection: "; + $answer = ; + if (! ($answer >= $min && $answer <= $max)) { + print "Invalid response, please try again.\n"; + } + } until $answer >= $min && $answer <= $max; + + return $answer; +} + +# +# Check for correct number of args +# + +if (scalar (@ARGV) != 2) { + print STDERR "ERROR: Invalid number of parameters.\n"; + exit; +} else { + $ptf_filename = $ARGV[0]; + $target_filename = $ARGV[1]; +} + +# +# Check to see if the specified file exists +# + +if (! -e $ptf_filename) { + print STDERR "ERROR: Could not open SYSTEM ptf file.\n"; + exit; +} + +# +# startup the parser. +# +$system = SystemPTF->new (filename => $ptf_filename); +if (!$system) { + print STDERR "ERROR: Specified file is not a SYSTEM ptf file.\n"; + exit; +} + +# +# Grab listing of Nios II processors and force user to select one: +# + +print "\n--- Please select which CPU you wish to build the kernel against:\n\n"; + +my @cpulist = $system->getCPUList ('altera_nios2'); +my %cpuinfo; + +$index = 1; +foreach my $cpu (@cpulist) { + my $cpu_module = $system->getCPU ($cpu); + if ($cpu_module->isEnabled ()) { + my $class = $cpu_module->getClass(); + my $type = $cpu_module->getWSAAssignment('cpu_selection'); + my $version = $cpu_module->getVersion(); + + print "($index) $cpu - Class: $class Type: $type Version: $version\n"; + } + $index += 1; +} + +print "\n"; + +my $cpu_selection = $cpulist[request_answer (1, $index - 1) - 1]; + +# +# Grab list of memory devices that $cpu_selection is hooked up to: +# +my @modulelist = $system->getSlaveModules ($cpu_selection); +my %cfiinfo; +my %meminfo; +foreach my $module_name (@modulelist) { + my $module = $system->getModule ($module_name); + my $class = $module->getClass (); + + if ($module->isEnabled ()) { + if ($class eq 'altera_avalon_cfi_flash') { + $cfiinfo{$module_name}{class} = $class; + $cfiinfo{$module_name}{size} = $module->getSize(); + } + + if ($module->isMemoryDevice()) { + $meminfo{$module_name}{class} = $class; + $meminfo{$module_name}{size} = $module->getSize(); + } + } +} + +# +# Select an upload device: +# +print "\n--- Please select a device to upload the kernel to:\n\n"; + +$index = 1; +foreach my $name (keys (%cfiinfo)) { + my $size = hex ($cfiinfo{$name}{size}); + print "($index) $name\n\tClass: $cfiinfo{$name}{class}\n\tSize: $size bytes\n\n"; + $index += 1; +} + +my @cfilist = keys (%cfiinfo); +my $cfi_selected = $cfilist[request_answer (1, $index - 1) - 1]; + +delete $meminfo{$cfi_selected}; + +# +# Select program memory to execute kernel from: +# +print "\n--- Please select a device to execute kernel from:\n\n"; + +$index = 1; +foreach my $name (keys (%meminfo)) { + my $size = hex ($meminfo{$name}{size}); + print "($index) $name\n\tClass: $meminfo{$name}{class}\n\tSize: $size bytes\n\n"; + $index += 1; +} + +my @memlist = keys (%meminfo); +my $mem_selected = $memlist[request_answer (1, $index - 1) - 1]; + +print "\n--- Summary using\n\n"; +print "PTF: $ptf_filename\n"; +print "CPU: $cpu_selection\n"; +print "Device to upload to: $cfi_selected\n"; +print "Program memory to execute from: $mem_selected\n"; + +# +# Write settings out to Makefile fragment +# +open (HWMK, ">$target_filename") || + die "Could not write to $target_filename"; + +print HWMK "SYSPTF = $ptf_filename\n"; +print HWMK "CPU = $cpu_selection\n"; +print HWMK "UPLMEM = $cfi_selected\n"; +print HWMK "EXEMEM = $mem_selected\n"; + +close (HWMK); + +print "\n--- Settings written to $target_filename\n\n"; \ No newline at end of file diff --git a/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm b/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm new file mode 100644 index 00000000..e15c26b0 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/BasicModule.pm @@ -0,0 +1,267 @@ +package BasicModule; + +require PTF::SystemPTF; +require PTF::SystemPTF::Module; +use strict; + +# Description: Prints an error message to stdout. This should prefix each line +# with "#error " so that it can be properly read by the C +# pre-processor. +# Args: $module_name: name of module that was is required by driver +# $class_name: name of device class that module belongs to. +sub print_error_name_used { + my ($class, $module_name, $class_name) = @_; + + print "#error The kernel requires that the $class->required_class_name device be named as $module_name.\n"; + print "#error The current hardware has $module_name defined as a(n) $class_name device.\n"; + print "#error This will cause the kernel to fail.\n"; + print "#error Please rename the current $module_name device to something else in SOPC Builder.\n"; +} + +# Description: This casts the base address to a specific data type +# By default, it does not cast the base address to +# anything. +sub base_address_cast { + my ($class, $port_name) = @_; + return; +} + +# Description: This sub-routine prints out a prefix that is shown only once +# before any translations take place. +sub print_prefix { + my ($class, $system) = @_; + printf ("\n"); +} + +# Description: Prints a set of lines to stdout that re-defines all symbols +# related to $module_name to the symbols required by the driver. +# Typically starts off with "#undefine ..." statements followed +# by one or more "#define statements". +# Args: $required_module_name: the module name that's expected by the kernel. +# $module_name: the name of the module that was found in the PTF file. +sub translate { + my ($class, $system, $required_module_name, $module_name) = @_; + + # get the necessary info about the module + my $module = $system->getModule ($module_name); + my @port_names = $module->getPorts (); + + my $boolean_base_address_cast = 0; + if (scalar (@port_names) > 1) { + foreach my $port_name (@port_names) { + my $cast = $class->base_address_cast ($port_name); + if (defined ($cast)) { + $boolean_base_address_cast = 1; + last; + } + } + } else { + my $cast = $class->base_address_cast; + if (defined ($cast)) { + $boolean_base_address_cast = 1; + } + } + + if ($module_name eq $required_module_name && + !$boolean_base_address_cast) { + printf ("/* No translation necessary for $module_name */\n\n"); + return; + } + + # undefine the original entries + print "/* Redefining $module_name -> $required_module_name */\n"; + if (scalar (@port_names) == 1) { + my $irq = $module->getIRQ (); + print "#undef na_" . $module_name . "\n"; + if (defined ($irq)) { + print "#undef na_" . $module_name . "_irq\n"; + } + print "\n"; + } else { + foreach my $port_name (@port_names) { + print "#undef na_" . $module_name . "_" . + $port_name . "\n"; + my $irq = $module->getIRQ ($port_name); + if (defined ($irq)) { + print "#undef na_" . $module_name . "_" . + $port_name . "_irq\n"; + } + print "\n"; + } + } + + if (scalar (@port_names) == 1) { + # set up a string to pass to printf that will output the correct + # #define base address statement. + + # turn on the high bit for the base address to bypass cache. + my $base_address = $module->getBaseAddress (); + $base_address = hex ($base_address) | 0x80000000; + + my $cast = $class->base_address_cast; + $class->print_define_line ($required_module_name, + undef, "addr", $cast, $base_address); + + # print out an IRQ define statement if necessary + my $irq = $module->getIRQ (); + if (defined ($irq)) { + $class->print_define_line ($required_module_name, + undef, "irq", undef, $irq); + } + printf ("\n"); + } else { + foreach my $port_name (@port_names) { + my $cast = $class->base_address_cast ($port_name); + my $base_address = $module->getBaseAddress ($port_name); + $base_address = hex ($base_address) | 0x80000000; + $class->print_define_line ($required_module_name, + $port_name, "addr", $cast, $base_address); + + my $irq = $module->getIRQ ($port_name); + if (defined ($irq)) { + $class->print_define_line ( + $required_module_name, $port_name, + "irq", undef, $irq); + } + + print "\n"; + } + } +} + +# Description: The following sub-routine prints out "undef" or "define" +# statements based on the arguments received. +# Args: $name: "define" or "undef" +# $port: name of port (if applicable) +# $type: "addr" or "irq" +# $cast: data type to cast base address to (if applicable) +# $value: value of symbol to be defined (if applicable) +sub print_define_line { + my ($class, $name, $port, $type, $cast, $value) = @_; + + # construct the symbol that is being used + my $symbol .= "na_"; + $symbol .= $name; + + $symbol .= defined ($port) ? "_" . $port : ""; + $symbol .= $type eq "irq" ? "_irq" : ""; + + my $string_value; + if ($type eq "addr") { + $string_value = sprintf ("%#010x", $value); + if (defined $cast) { + $string_value = "(($cast*) $string_value)"; + } + } else { + $string_value = $value; + } + printf ("%-41s %30s\n", "#define $symbol", $string_value); +} + +# Description: This sub-routine prints out a prefix that is shown only once +# after any translations take place. +sub print_suffix { + my ($class, $system) = @_; + # intentionally left empty +} + +# Description: The following function allows the class to further determine if +# the module is valid. For instance, the timer class requires +# that the selected module does not have a fixed period. +# This function returns true by default which basically means +# that all modules belonging to class are valid. +sub is_module_valid { + my ($class, $system, $module_name) = @_; + return 1; +} + +# Description: This sub-routine is required. It is executed by the +# "../gen_nios2_system_h.pl" script whenever any devices of type +# $class->required_class_name are found in the PTF file. +# +# It looks for any conflicting module names first. If any are +# found, "print_error_name_used" is called and this perl module +# exits. +# +# It then goes through the list of module names found in the PTF +# file that are of type $class->required_class_name and maps them to the +# list of unused names in $class->required_module_names. +# +# Finally, it will call the "translate" sub-routine to output the +# symbols required by the driver. +# Args: $system: a variable containing a reference to the system.ptf file that +# provides full access to any information in the file. +# @found_module_names: a list of module names that are of type +# $class->required_class_name +sub run2 { + my ($class, $system, @found_module_names) = @_; + + # initialize a mapping of required module names to actual module names + my %module_map; + foreach my $module_name ($class->required_module_names) { + $module_map{$module_name} = ""; + } + + # if the required module name is already in use in the PTF file for a + # different device class, flag it as an error. + my $error_found = 0; + foreach my $module_name ($class->required_module_names) { + my $module = $system->getModule ($module_name); + + if (!defined ($module)) { + next; + } + + my $class_name = $module->getClass (); + if ($class_name ne $class->required_class_name) { + $class->print_error_name_used ($class, $module_name, $class_name); + $error_found = 1; + } + } + + # if errors were found, then there's no point in continuing. + if ($error_found == 1) { + return; + } + + # Run through list of modules that belong to the class and start + # mapping each module name to the first unused required module name + # as defined above + FOUND_MOD_LOOP: foreach my $module_name (@found_module_names) { + + # If the module name has already been used, then continue + # to the next one. + foreach my $required_module_name ($class->required_module_names) { + if ($module_map{$required_module_name} eq $module_name) { + next FOUND_MOD_LOOP; + } + } + + # assertion: $module_name is not mapped yet. + foreach my $required_module_name ($class->required_module_names) { + if ($module_map{$required_module_name} ne "") { + next; + } + + if ($class->is_module_valid ($system, $module_name)) { + $module_map{$required_module_name} = $module_name; + } + last; + } + } + + $class->print_prefix ($system); + + # Now that everything's been mapped (or as close as we're going to get + # to it being mapped), start printing out the literal translation. + foreach my $required_module_name ($class->required_module_names) { + my $module_name = $module_map{$required_module_name}; + if (length ($module_name) > 0) { + $class->translate ($system, $required_module_name, $module_name); + } + } + + $class->print_suffix ($system); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm new file mode 100644 index 00000000..dada452a --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_cf.pm @@ -0,0 +1,18 @@ +package altera_avalon_cf; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + "ide" +} + +sub required_class_name { + "altera_avalon_cf" +} + +sub run { + altera_avalon_cf->run2(@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm new file mode 100644 index 00000000..22bb9c9b --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_jtag_uart.pm @@ -0,0 +1,18 @@ +package altera_avalon_jtag_uart; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + ("jtag_uart") +} + +sub required_class_name { + "altera_avalon_jtag_uart"; +} + +sub run { + altera_avalon_jtag_uart->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm new file mode 100644 index 00000000..5a29b7eb --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_lan91c111.pm @@ -0,0 +1,38 @@ +package altera_avalon_lan91c111; + +require PTF::SystemPTF; +require PTF::SystemPTF::Module; +use base qw(BasicModule); +use strict; + +sub required_module_names { + "enet" +} + +sub required_class_name { + "altera_avalon_lan91c111" +} + +sub translate { + my $class = shift; + my ($system, $required_module_name, $module_name) = @_; + $class->SUPER::translate (@_); + + my $module = $system->getModule ($module_name); + + my $offset_keyword = "LAN91C111_REGISTERS_OFFSET"; + my $offset = $module->getWSAConstant ($offset_keyword); + printf ("%-41s %30s\n", "#define $offset_keyword", $offset); + + my $width_keyword = "LAN91C111_DATA_BUS_WIDTH"; + my $width = $module->getWSAConstant ($width_keyword); + printf ("%-41s %30s\n", "#define $width_keyword", $width); + + print "\n"; +} + +sub run { + altera_avalon_lan91c111->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm new file mode 100644 index 00000000..afdbcae3 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_pio.pm @@ -0,0 +1,46 @@ +package altera_avalon_pio; + +require PTF::SystemPTF; +require PTF::SystemPTF::Module; +use strict; + +sub run { + my ($system, @pio_names) = @_; + + print "#ifndef __ASSEMBLY__\n"; + print "#include \n"; + print "#endif\n\n"; + + foreach my $pio_name (@pio_names) { + my $module = $system->getModule ($pio_name); + + # get all the relevant information + my $base_address = $module->getBaseAddress (); + $base_address = hex ($base_address) | 0x80000000; + my $irq = $module->getIRQ (); + + print "/* Casting base addresses to the appropriate structure */\n"; + + # undefine all the old symbols first + print "#undef na_${pio_name}\n"; + if (defined ($irq)) { + print "#undef na_${pio_name}_irq\n"; + print "\n"; + } + + # define base address + $base_address = sprintf ("%#010x", $base_address); + printf ("%-41s %30s\n", "#define na_${pio_name}", + "((np_pio*) ${base_address})"); + + # define irq + if (defined ($irq)) { + printf ("%-41s %30s\n", "#define na_${pio_name}_irq", + $irq); + } + + print "\n"; + } +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm new file mode 100644 index 00000000..719a22c1 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_spi.pm @@ -0,0 +1,30 @@ +package altera_avalon_spi; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + "spi" +} + +sub required_class_name { + "altera_avalon_spi" +} + +sub base_address_cast { + "np_spi" +} + +sub print_prefix { + my ($class, $system) = @_; + + print "#ifndef __ASSEMBLY__\n"; + print "#include \n"; + print "#endif\n\n"; +} + +sub run { + altera_avalon_spi->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm new file mode 100644 index 00000000..deb98260 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_sysid.pm @@ -0,0 +1,18 @@ +package altera_avalon_sysid; + +use base qw(BasicModule); +use strict; + +sub required_class_name { + "altera_avalon_sysid" +} + +sub required_module_names { + "sysid" +} + +sub run { + altera_avalon_sysid->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm new file mode 100644 index 00000000..495ccdcf --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_timer.pm @@ -0,0 +1,46 @@ +package altera_avalon_timer; + +use base qw(BasicModule); +use strict; + +sub required_class_name { + "altera_avalon_timer"; +} + +sub required_module_names { + "timer0" +} + +sub print_prefix { + my ($class, $system) = @_; + + print "\n"; + print "#ifndef __ASSEMBLY__\n"; + print "#include \n"; + print "#endif\n"; + print "\n"; +} + +sub base_address_cast { + "np_timer" +} + +# only timers with a non-fixed-period are valid +sub is_module_valid { + my ($class, $system, $module_name) = @_; + + my $module = $system->getModule ($module_name); + my $fixed_period = $module->getWSAAssignment ('fixed_period'); + + if ($fixed_period eq '0') { + return 1; + } else { + return 0; + } +} + +sub run { + altera_avalon_timer->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm new file mode 100644 index 00000000..abf48d7c --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/altera_avalon_uart.pm @@ -0,0 +1,44 @@ +package altera_avalon_uart; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + ("uart0", "uart1", "uart2", "uart3") +} + +sub required_class_name { + "altera_avalon_uart"; +} + +sub base_address_cast { + "np_uart" +} + +sub print_prefix { + my ($class, $system) = @_; + + print "#ifndef __ASSEMBLY__\n"; + print "#include \n"; + print "#endif\n\n"; +} + +sub translate { + my $class = shift; + my ($system, $required_module_name, $module_name) = @_; + + $class->SUPER::translate (@_); + + if (!defined ($altera_avalon_uart::default_uart)) { + print "/* The default uart is always the first one found in the PTF file */\n"; + print "#define nasys_printf_uart na_$required_module_name\n\n"; + $altera_avalon_uart::default_uart = $required_module_name; + } + +} + +sub run { + altera_avalon_uart->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm b/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm new file mode 100644 index 00000000..fdd727b8 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/mtip_avalon_10_100_mac.pm @@ -0,0 +1,18 @@ +package mtip_avalon_10_100_mac; + +use base qw(BasicModule); +use strict; + +sub required_class_name { + "mtip_avalon_10_100_mac"; +} + +sub required_module_names { + "mtip_mac" +} + +sub run { + mtip_avalon_10_100_mac->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm new file mode 100644 index 00000000..5985c2f6 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_dm9000.pm @@ -0,0 +1,18 @@ +package mtx_avalon_dm9000; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + "dm9000" +} + +sub required_class_name { + "mtx_avalon_dm9000" +} + +sub run { + mtx_avalon_dm9000->run2(@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm new file mode 100644 index 00000000..e70ffa38 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/mtx_avalon_isp1161a1.pm @@ -0,0 +1,18 @@ +package mtx_avalon_isp1161a1; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + "usb" +} + +sub required_class_name { + "mtx_avalon_isp1161a1"; +} + +sub run { + mtx_avalon_isp1161a1->run2(@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm b/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm new file mode 100644 index 00000000..7b580b53 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/opencores_ethernet_mac.pm @@ -0,0 +1,18 @@ +package opencores_ethernet_mac; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + "igor_mac" +} + +sub required_class_name { + "opencores_ethernet_mac" +} + +sub run { + opencores_ethernet_mac->run2 (@_); +} + +1; diff --git a/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm b/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm new file mode 100644 index 00000000..512d12c5 --- /dev/null +++ b/arch/nios2nommu/scripts/nios2_system.h/opencores_i2c.pm @@ -0,0 +1,18 @@ +package opencores_i2c; + +use base qw(BasicModule); +use strict; + +sub required_module_names { + ("i2c_0", "i2c_1") +} + +sub required_class_name { + "opencores_i2c"; +} + +sub run { + opencores_i2c->run2 (@_); +} + +1; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 6a461d4c..9bbf695e 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -235,6 +235,41 @@ endchoice source "arch/sh/mm/Kconfig" +config SH_CONCAT_FS + bool "Fixup fileystem concated to kernel image" + default n + help + Some SH platforms boot a kernel with the root filesystem at the end + of the kernel binary (Where the BSS appears) and enabling this option + moved the filesystem to the end of the kernel and reserves the memory + it occupies. + +config MEMORY_START + hex "Physical memory start address" + default "0x08000000" + ---help--- + Computers built with Hitachi SuperH processors always + map the ROM starting at address zero. But the processor + does not specify the range that RAM takes. + + The physical memory (RAM) start address will be automatically + set to 08000000. Other platforms, such as the Solution Engine + boards typically map RAM at 0C000000. + + Tweak this only when porting to a new machine which does not + already have a defconfig. Changing it from the known correct + value on any of the known systems will only lead to disaster. + +config MEMORY_SIZE + hex "Physical memory size" + default "0x00400000" + help + This sets the default memory size assumed by your SH kernel. It can + be overridden as normal by the 'mem=' argument on the kernel command + line. If unsure, consult your board specifications or just leave it + as 0x00400000 which was the default value before this became + configurable. + config CF_ENABLER bool "Compact Flash Enabler support" depends on SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_SH03 diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 26d62ff5..7b75cc09 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -157,7 +157,7 @@ include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \ include/config/auto.conf FORCE @echo -n ' SYMLINK include/asm-sh/mach -> ' $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi - $(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \ + $(Q)if [ -d $(srctree)/include/asm-sh/$(incdir-y) ]; then \ echo -e 'include/asm-sh/$(incdir-y)'; \ ln -fsn $(incdir-prefix)$(incdir-y) \ include/asm-sh/mach; \ diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c index a1d51d5f..ea255d30 100644 --- a/arch/sh/boards/se/770x/setup.c +++ b/arch/sh/boards/se/770x/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.1.2.4 2002/03/02 21:57:07 lethal Exp $ +/* $Id: setup.c,v 1.3 2003/05/04 19:29:47 lethal Exp $ * * linux/arch/sh/boards/se/770x/setup.c * diff --git a/arch/sh/boards/snapgear/Makefile b/arch/sh/boards/snapgear/Makefile index 59fc976b..fbe3ab1f 100644 --- a/arch/sh/boards/snapgear/Makefile +++ b/arch/sh/boards/snapgear/Makefile @@ -2,5 +2,5 @@ # Makefile for the SnapGear specific parts of the kernel # -obj-y := setup.o io.o rtc.o +obj-y := setup.o io.o diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c index 1659fdd6..e4e37cac 100644 --- a/arch/sh/boards/snapgear/rtc.c +++ b/arch/sh/boards/snapgear/rtc.c @@ -18,6 +18,7 @@ #include #include #include +#include static int use_ds1302; diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c index 650fb364..5d2ed14d 100644 --- a/arch/sh/boards/snapgear/setup.c +++ b/arch/sh/boards/snapgear/setup.c @@ -25,7 +25,10 @@ #include #include -extern void secureedge5410_rtc_init(void); +#include +#include +#include + extern void pcibios_init(void); /****************************************************************************/ @@ -35,9 +38,14 @@ extern void pcibios_init(void); static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id) { - volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000; + volatile char dummy __attribute__((unused)) = * (volatile char *)0xb8000000; +#ifdef CONFIG_LEDMAN + extern void ledman_signalreset(void); + ledman_signalreset(); +#else printk("SnapGear: erase switch interrupt!\n"); +#endif return IRQ_HANDLED; } @@ -69,10 +77,13 @@ module_init(eraseconfig_init); */ static struct ipr_data snapgear_ipr_map[] = { - make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY); - make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY); - make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY); - make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY); + { IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY }, + { IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY }, + { IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY }, + { IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY }, + { RTC_PRI_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, + { RTC_CUI_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, + { RTC_ATI_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, }; static void __init init_snapgear_IRQ(void) @@ -86,11 +97,102 @@ static void __init init_snapgear_IRQ(void) } /* + * This is set up by the setup-routine at boot-time + */ +#define PARAM ((unsigned char *)empty_zero_page) + +#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c)) +#define INITRD_START (*(unsigned long *) (PARAM+0x010)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014)) + +static struct resource sg_mtd_ram_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platdata_mtd_ram sg_mtd_ram_data = { + .mapname = "Romfs", + .bankwidth = 1, + .root_dev = 1, +}; + +static struct platform_device sg_mtd_ram_device = { + .name = "mtd-ram", + .id = 0, + .dev.platform_data = &sg_mtd_ram_data, + .num_resources = 1, + .resource = &sg_mtd_ram_resource, +}; + +#ifdef CONFIG_RTC_DRV_DS1302 +static struct platform_device sg_rtc_device = { + .name = "ds1302", + .id = -1, + .num_resources = 0, +}; +#endif + +#ifdef CONFIG_RTC_DRV_SH +static struct resource sh_rtc_resources[] = { + [0] = { + .start = RTC_BASE, + .end = RTC_BASE + 0x58 - 1, + .flags = IORESOURCE_IO, + }, + [1] = { + /* Period IRQ */ + .start = RTC_PRI_IRQ, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* Carry IRQ */ + .start = RTC_CUI_IRQ, + .flags = IORESOURCE_IRQ, + }, + [3] = { + /* Alarm IRQ */ + .start = RTC_ATI_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sh_rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(sh_rtc_resources), + .resource = sh_rtc_resources, +}; +#endif + +static int __init sg_devices_setup(void) +{ + int ret = 0, ret2 = 0; + + if (sg_mtd_ram_resource.start) + ret = platform_device_register(&sg_mtd_ram_device); + +#ifdef CONFIG_RTC_DRV_DS1302 + ret2 = platform_device_register(&sg_rtc_device); + if (ret2) +#endif + { +#ifdef CONFIG_RTC_DRV_SH + ret2 = platform_device_register(&sh_rtc_device); +#endif + } + return ret ? ret : ret2; +} + +__initcall(sg_devices_setup); + +/* * Initialize the board */ static void __init snapgear_setup(char **cmdline_p) { - board_time_init = secureedge5410_rtc_init; + if (!LOADER_TYPE && INITRD_START) { + sg_mtd_ram_resource.start = INITRD_START; + sg_mtd_ram_resource.end = INITRD_START + INITRD_SIZE - 1; + } } /* diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c index 53dd893d..ca72cc51 100644 --- a/arch/sh/drivers/pci/ops-snapgear.c +++ b/arch/sh/drivers/pci/ops-snapgear.c @@ -35,7 +35,7 @@ static struct resource sh7751_io_resource = { static struct resource sh7751_mem_resource = { .name = "SH7751 mem", .start = SNAPGEAR_PCI_MEM, - .end = SNAPGEAR_PCI_MEM + (64*1024*1024) - 1, /* 64MiB mem */ + .end = SNAPGEAR_PCI_MEM + (32*1024*1024) - 1, /* 32MiB mem */ .flags = IORESOURCE_MEM, }; diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c index ecf16344..ffb87908 100644 --- a/arch/sh/drivers/pci/pci-auto.c +++ b/arch/sh/drivers/pci/pci-auto.c @@ -184,7 +184,11 @@ retry: bar_size = ~(bar_response & addr_mask) + 1; /* Allocate a base address */ - bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; + bar_value = (*lower_limit + (bar_size - 1)) & ~(bar_size - 1); + + /* some combos can wrap, check for this */ + if (bar_value < *lower_limit) + continue; if ((bar_value + bar_size) > *upper_limit) { if (bar_response & PCI_BASE_ADDRESS_SPACE) { diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index f5f53d14..b254501a 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -33,8 +33,12 @@ ENTRY(empty_zero_page) .long 0x00360000 /* INITRD_START */ .long 0x000a0000 /* INITRD_SIZE */ .long 0 + .balign 256,0,256 + /* Command line goes here */ +#ifdef CONFIG_CMDLINE_BOOL + .ascii CONFIG_CMDLINE "\0" +#endif .balign 4096,0,4096 - .text /* * Condition at the entry of _stext: @@ -73,6 +77,13 @@ ENTRY(_stext) sub r1, r0 ! ldc r0, r7_bank ! ... and initial thread_info +#if defined(CONFIG_SH_CONCAT_FS) + ! move the fs to after the bss + mov.l 7f, r0 + jsr @r0 + nop +#endif + ! Clear BSS area mov.l 3f, r1 add #4, r1 @@ -101,3 +112,6 @@ ENTRY(_stext) 4: .long _end 5: .long start_kernel 6: .long sh_cpu_init +#if defined(CONFIG_SH_CONCAT_FS) +7: .long copy_romfs +#endif diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index a52b13ac..4a48c024 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -455,7 +455,6 @@ out: unsigned long get_wchan(struct task_struct *p) { - unsigned long schedule_frame; unsigned long pc; if (!p || p == current || p->state == TASK_RUNNING) @@ -465,10 +464,13 @@ unsigned long get_wchan(struct task_struct *p) * The same comment as on the Alpha applies here, too ... */ pc = thread_saved_pc(p); +#ifdef CONFIG_FRAME_POINTER if (in_sched_functions(pc)) { + unsigned long schedule_frame; schedule_frame = ((unsigned long *)(long)p->thread.sp)[1]; - return (unsigned long)((unsigned long *)schedule_frame)[1]; + pc = (unsigned long)((unsigned long *)schedule_frame)[1]; } +#endif return pc; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 36d86f9a..a051b060 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -233,7 +233,7 @@ void __init setup_arch(char **cmdline_p) unsigned long start_pfn, max_pfn, max_low_pfn; #ifdef CONFIG_CMDLINE_BOOL - strcpy(COMMAND_LINE, CONFIG_CMDLINE); + strcpy(COMMAND_LINE, CONFIG_CMDLINE); #endif ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); @@ -272,6 +272,11 @@ void __init setup_arch(char **cmdline_p) * Partially used pages are not usable - thus * we are rounding upwards: */ +#if defined(CONFIG_BLK_DEV_INITRD) || defined(CONFIG_SH_CONCAT_FS) + if (INITRD_START == __pa(_end)) + start_pfn = PFN_UP(__pa(_end) + INITRD_SIZE); + else +#endif start_pfn = PFN_UP(__pa(_end)); /* @@ -331,9 +336,13 @@ void __init setup_arch(char **cmdline_p) if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { + if (INITRD_START == __pa(_end)) + initrd_start = INITRD_START + PAGE_OFFSET; + else { reserve_bootmem_node(NODE_DATA(0), INITRD_START+__MEMORY_START, INITRD_SIZE); initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + } initrd_end = initrd_start + INITRD_SIZE; } else { printk("initrd extends beyond end of memory " @@ -599,3 +608,66 @@ static int __init kgdb_parse_options(char *options) } __setup("kgdb=", kgdb_parse_options); #endif /* CONFIG_SH_KGDB */ + +#if defined(CONFIG_SH_CONCAT_FS) +/* + * do not call printk in here, bad things will happen, the kernel isn't + * actually up yet, we are called from head.S before BSS is cleared. + */ + +extern void copy_romfs(void); +void copy_romfs() +{ +#ifdef CONFIG_SH_SECUREEDGE5410 + volatile char dummy; +#define SERVICE_WATCHDOG() (dummy = * (volatile char *) 0xb8000000) +#else +#define SERVICE_WATCHDOG() +#endif + unsigned char *sp, *dp; + unsigned long len; + /* + * we used to use __bss_start, but that is padded to 4K now and doesn't + * work, basically we need the last non-padded symbol before __bss_start + * and that is now __machvec_end + */ + extern long __machvec_end; +#define CURRENT_ROMFS_LOC ((unsigned long)(&__machvec_end)) +#ifdef CONFIG_SH_ROMBOOT + extern int _mem_start, _rom_store; + sp = (unsigned char *) CURRENT_ROMFS_LOC - ((_mem_start - _rom_store) / 4); +#else + sp = (unsigned char *) CURRENT_ROMFS_LOC; +#endif + dp = (unsigned char *) &_end[0]; + + if (memcmp(&sp[0], "-rom1fs-", 8) == 0) { + /* romfs */ + memcpy(&len, sp, sizeof(len)); + len = be32_to_cpu(len); + } else if (sp[0]==0x45 && sp[1]==0x3d && sp[2]==0xcd && sp[3]==0x28) { + /* cramfs */ + memcpy(&len, &sp[4], sizeof(len)); + } else { + *dp = 0; /* make sure we don't see an old FS there */ + return; + } + + len = (len + 0xfff) & ~0xfff; /* make it a multiple of a page */ + LOADER_TYPE = 0; + INITRD_SIZE = len; + INITRD_START = __pa(_end); + + sp += len; + dp += len; + + /* copy backwards to avoid writing over ourselves */ + SERVICE_WATCHDOG(); + while (dp >= ((unsigned char *) (&_end[0]))) { + *dp-- = *sp--; + if ((((unsigned long) dp) & 0x7ffff) == 0) + SERVICE_WATCHDOG(); + } + SERVICE_WATCHDOG(); +} +#endif diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S index cbdd0d40..be2643b1 100644 --- a/arch/sh/lib/checksum.S +++ b/arch/sh/lib/checksum.S @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.10 2001/07/06 13:11:32 gniibe Exp $ +/* $Id: checksum.S,v 1.1.1.1 2001/10/15 20:44:53 mrbrown Exp $ * * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket diff --git a/arch/sh/lib/memchr.S b/arch/sh/lib/memchr.S index bc6036ad..3e4bf0e2 100644 --- a/arch/sh/lib/memchr.S +++ b/arch/sh/lib/memchr.S @@ -1,4 +1,4 @@ -/* $Id: memchr.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ +/* $Id: memchr.S,v 1.1.1.1 2001/10/15 20:44:53 mrbrown Exp $ * * "memchr" implementation of SuperH * diff --git a/arch/sh/lib/memcpy.S b/arch/sh/lib/memcpy.S index 232fab34..d484a8a7 100644 --- a/arch/sh/lib/memcpy.S +++ b/arch/sh/lib/memcpy.S @@ -1,4 +1,4 @@ -/* $Id: memcpy.S,v 1.3 2001/07/27 11:50:52 gniibe Exp $ +/* $Id: memcpy.S,v 1.1.1.1 2001/10/15 20:44:53 mrbrown Exp $ * * "memcpy" implementation of SuperH * diff --git a/arch/sh/lib/memmove.S b/arch/sh/lib/memmove.S index 5a2211f0..701ab889 100644 --- a/arch/sh/lib/memmove.S +++ b/arch/sh/lib/memmove.S @@ -1,4 +1,4 @@ -/* $Id: memmove.S,v 1.2 2001/07/27 11:51:09 gniibe Exp $ +/* $Id: memmove.S,v 1.3 2003/05/04 19:29:54 lethal Exp $ * * "memmove" implementation of SuperH * diff --git a/arch/sh/lib/memset.S b/arch/sh/lib/memset.S index af91fe2b..9dd7a79b 100644 --- a/arch/sh/lib/memset.S +++ b/arch/sh/lib/memset.S @@ -1,4 +1,4 @@ -/* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ +/* $Id: memset.S,v 1.1.1.1 2001/10/15 20:44:53 mrbrown Exp $ * * "memset" implementation of SuperH * diff --git a/arch/sh/lib/strlen.S b/arch/sh/lib/strlen.S index f8ab2960..ad0e1df3 100644 --- a/arch/sh/lib/strlen.S +++ b/arch/sh/lib/strlen.S @@ -1,4 +1,4 @@ -/* $Id: strlen.S,v 1.2 2001/06/29 14:07:15 gniibe Exp $ +/* $Id: strlen.S,v 1.1.1.1 2001/10/15 20:44:53 mrbrown Exp $ * * "strlen" implementation of SuperH * diff --git a/arch/um/Kconfig.arch b/arch/um/Kconfig.arch new file mode 120000 index 00000000..129d6e7c --- /dev/null +++ b/arch/um/Kconfig.arch @@ -0,0 +1 @@ +Kconfig.i386 \ No newline at end of file diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 47b812b3..0a33dc16 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -11,6 +11,10 @@ #include "sysdep/stub.h" #include "kern_constants.h" +#ifndef CLONE_PARENT +# define CLONE_PARENT 0x00008000 +#endif + /* This is in a separate file because it needs to be compiled with any * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled * diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 2f8c7946..ba20718a 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -23,6 +23,6 @@ CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ echo -DHAVE_AIO_ABI ) -CFLAGS_aio.o += $(HAVE_AIO_ABI) +CFLAGS_aio.o += -I/usr/include $(HAVE_AIO_ABI) include arch/um/scripts/Makefile.rules diff --git a/arch/v850/lib/checksum.c b/arch/v850/lib/checksum.c index fa587263..825d39c3 100644 --- a/arch/v850/lib/checksum.c +++ b/arch/v850/lib/checksum.c @@ -14,7 +14,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: checksum.c,v 1.1 2002/09/28 14:58:40 gerg Exp $ + * $Id: checksum.c,v 1.4 2005/08/31 01:54:19 gerg Exp $ */ #include #include diff --git a/block/as-iosched.c b/block/as-iosched.c index 50b95e4c..0b0ae53b 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -355,11 +355,20 @@ as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2) static struct request * as_find_next_rq(struct as_data *ad, struct request *last) { +#if 0 // mask by Victor Yu. 02-12-2007 struct rb_node *rbnext = rb_next(&last->rb_node); struct rb_node *rbprev = rb_prev(&last->rb_node); +#else + struct rb_node *rbnext = rb_next(&last->u.rb_node); + struct rb_node *rbprev = rb_prev(&last->u.rb_node); +#endif struct request *next = NULL, *prev = NULL; +#if 0 // mask by Victor Yu. 02-12-2007 BUG_ON(RB_EMPTY_NODE(&last->rb_node)); +#else + BUG_ON(RB_EMPTY_NODE(&last->u.rb_node)); +#endif if (rbprev) prev = rb_entry_rq(rbprev); @@ -370,7 +379,11 @@ as_find_next_rq(struct as_data *ad, struct request *last) const int data_dir = rq_is_sync(last); rbnext = rb_first(&ad->sort_list[data_dir]); +#if 0 // mask by Victor Yu. 02-12-2007 if (rbnext && rbnext != &last->rb_node) +#else + if (rbnext && rbnext != &last->u.rb_node) +#endif next = rb_entry_rq(rbnext); } @@ -931,7 +944,11 @@ static void as_move_to_dispatch(struct as_data *ad, struct request *rq) { const int data_dir = rq_is_sync(rq); +#if 0 // mask by Victor Yu. 02-12-2007 BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); +#else + BUG_ON(RB_EMPTY_NODE(&rq->u.rb_node)); +#endif as_antic_stop(ad); ad->antic_status = ANTIC_OFF; diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index b7c5b34c..b617220b 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -75,7 +75,11 @@ deadline_del_rq_rb(struct deadline_data *dd, struct request *rq) const int data_dir = rq_data_dir(rq); if (dd->next_rq[data_dir] == rq) { +#if 0 // mask by Victor Yu. 02-12-2007 struct rb_node *rbnext = rb_next(&rq->rb_node); +#else + struct rb_node *rbnext = rb_next(&rq->u.rb_node); +#endif dd->next_rq[data_dir] = NULL; if (rbnext) @@ -198,7 +202,11 @@ static void deadline_move_request(struct deadline_data *dd, struct request *rq) { const int data_dir = rq_data_dir(rq); +#if 0 // mask by Victor Yu. 02-12-2007 struct rb_node *rbnext = rb_next(&rq->rb_node); +#else + struct rb_node *rbnext = rb_next(&rq->u.rb_node); +#endif dd->next_rq[READ] = NULL; dd->next_rq[WRITE] = NULL; diff --git a/block/elevator.c b/block/elevator.c index 8ccd1632..e9d88845 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -310,7 +310,11 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq) while (*p) { parent = *p; +#if 0 // mask by Victor Yu. 02-12-2007 __rq = rb_entry(parent, struct request, rb_node); +#else + __rq = rb_entry(parent, struct request, u.rb_node); +#endif if (rq->sector < __rq->sector) p = &(*p)->rb_left; @@ -320,8 +324,13 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq) return __rq; } +#if 0 // mask by Victor Yu. 02-12-2007 rb_link_node(&rq->rb_node, parent, p); rb_insert_color(&rq->rb_node, root); +#else + rb_link_node(&rq->u.rb_node, parent, p); + rb_insert_color(&rq->u.rb_node, root); +#endif return NULL; } @@ -329,9 +338,15 @@ EXPORT_SYMBOL(elv_rb_add); void elv_rb_del(struct rb_root *root, struct request *rq) { +#if 0 // mask by Victor Yu. 02-12-2007 BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); rb_erase(&rq->rb_node, root); RB_CLEAR_NODE(&rq->rb_node); +#else + BUG_ON(RB_EMPTY_NODE(&rq->u.rb_node)); + rb_erase(&rq->u.rb_node, root); + RB_CLEAR_NODE(&rq->u.rb_node); +#endif } EXPORT_SYMBOL(elv_rb_del); @@ -342,7 +357,11 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector) struct request *rq; while (n) { +#if 0 // mask by Victor Yu. 02-12-2007 rq = rb_entry(n, struct request, rb_node); +#else + rq = rb_entry(n, struct request, u.rb_node); +#endif if (sector < rq->sector) n = n->rb_left; @@ -1103,7 +1122,11 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) struct request *elv_rb_former_request(request_queue_t *q, struct request *rq) { +#if 0 // mask by Victor Yu. 02-12-2007 struct rb_node *rbprev = rb_prev(&rq->rb_node); +#else + struct rb_node *rbprev = rb_prev(&rq->u.rb_node); +#endif if (rbprev) return rb_entry_rq(rbprev); @@ -1115,7 +1138,11 @@ EXPORT_SYMBOL(elv_rb_former_request); struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq) { +#if 0 // mask by Victor Yu. 02-12-2007 struct rb_node *rbnext = rb_next(&rq->rb_node); +#else + struct rb_node *rbnext = rb_next(&rq->u.rb_node); +#endif if (rbnext) return rb_entry_rq(rbnext); diff --git a/block/ioctl.c b/block/ioctl.c index 58aab630..053bd0ef 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -220,7 +220,11 @@ EXPORT_SYMBOL_GPL(blkdev_driver_ioctl); int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) { +#if 0 // mask by Victor Yu. 02-12-2007 struct block_device *bdev = inode->i_bdev; +#else + struct block_device *bdev = inode->u.i_bdev; +#endif struct gendisk *disk = bdev->bd_disk; int ret, n; @@ -290,7 +294,11 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, ENOIOCTLCMD for unknown ioctls. */ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) { +#if 0 // mask by Victor Yu. 02-12-2007 struct block_device *bdev = file->f_dentry->d_inode->i_bdev; +#else + struct block_device *bdev = file->f_dentry->d_inode->u.i_bdev; +#endif struct gendisk *disk = bdev->bd_disk; int ret = -ENOIOCTLCMD; if (disk->fops->compat_ioctl) { diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9eaee664..ae207fc1 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -250,7 +250,11 @@ static void rq_init(request_queue_t *q, struct request *rq) rq->errors = 0; rq->bio = rq->biotail = NULL; INIT_HLIST_NODE(&rq->hash); +#if 0 // mask by Victor Yu. 02-12-2007 RB_CLEAR_NODE(&rq->rb_node); +#else + RB_CLEAR_NODE(&rq->u.rb_node); +#endif rq->ioprio = 0; rq->buffer = NULL; rq->ref_count = 1; @@ -262,7 +266,11 @@ static void rq_init(request_queue_t *q, struct request *rq) rq->sense = NULL; rq->end_io = NULL; rq->end_io_data = NULL; +#if 0 // mask by Victor Yu. 02-12-2007 rq->completion_data = NULL; +#else + rq->u.completion_data = NULL; +#endif } /** diff --git a/drivers/Makefile b/drivers/Makefile index 4ac14dab..749491ce 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_IPATH_CORE) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ +obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_SUPERH) += sh/ obj-$(CONFIG_GENERIC_TIME) += clocksource/ obj-$(CONFIG_DMA_ENGINE) += dma/ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 485aa87e..5eb13bb8 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -298,7 +299,11 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int error; +#if 0 // mask by Victor Yu. 02-12-2007 struct block_device *bdev = inode->i_bdev; +#else + struct block_device *bdev = inode->u.i_bdev; +#endif if (cmd != BLKFLSBUF) return -ENOTTY; @@ -344,7 +349,11 @@ static int rd_open(struct inode *inode, struct file *filp) unsigned unit = iminor(inode); if (rd_bdev[unit] == NULL) { +#if 0 // mask by Victor Yu. 02-12-2007 struct block_device *bdev = inode->i_bdev; +#else + struct block_device *bdev = inode->u.i_bdev; +#endif struct address_space *mapping; unsigned bsize; gfp_t gfp_mask; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2af12fc4..af983467 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -79,6 +79,48 @@ config VT_HW_CONSOLE_BINDING information. For framebuffer console users, please refer to . +config MOXA_KEYPAD + tristate "Moxa CPU MOXA ODM keypad support" + depends on ARCH_MOXART + help + Say Y here if you have any keypad support for Moxa CPU. + We are implement for MOXA ODM project. + +config MOXA_LCM0 + tristate "Moxa CPU MOXA ODM LCM module WG12864C support" + depends on ARCH_MOXART + help + Say Y here if you have any LCM module WG12864C support for Moxa CPU. + We are implement for MOXA ODM project. + +config MOXA_LCM1 + tristate "Moxa CPU MOXA ODM LCM module WG240128B support" + depends on ARCH_MOXART + help + Say Y here if you have any LCM module WG240128B support for Moxa CPU. + We are implement for MOXA ODM project. + +config MOXA_LCM2 + tristate "Moxa CPU MOXA ODM LCM module WG12232C support" + depends on ARCH_MOXART + help + Say Y here if you have any LCM module WG12232C support for Moxa CPU. + We are implement for MOXA ODM project. + +config MOXA_LCM3 + tristate "Moxa CPU MOXA ODM LCM module WG16080B support" + depends on ARCH_MOXART + help + Say Y here if you have any LCM module WG16080B support for Moxa CPU. + We are implement for MOXA ODM project. + +config UC71XX_GPIO + tristate "Moxa CPU UC71XX GPIO support" + depends on ARCH_MOXART + help + Say Y here if you have any GPIO support for Moxa CPU. + We are implement for UC71XX project. + config SERIAL_NONSTANDARD bool "Non-standard serial port support" ---help--- @@ -95,6 +137,24 @@ config SERIAL_NONSTANDARD Most people can say N here. +config NIOS_LCD_16207 + bool "Nios LCD 16207 device support" + depends on NIOS || NIOS2 + help + This driver supports the Nios LCD 16207 device. + +config NIOS_BUTTON + bool "Nios PIO buttons support" + depends on ALTERA_STRATIX || ALTERA_STRATIX_PRO || ALTERA_CYCLONE || ALTERA_STRATIX_II + ---help--- + This driver takes the 4 user buttons on Altera's Nios Development Kit + as a source of input: users can input '1','2','4' or '8' by pressing + one of the 4 buttons. The device node is a character device with a + major of 62 and minor of 0. Users can view input using the following + command: + $ cat /dev/btn + where /dev/btn is the device node file. + config COMPUTONE tristate "Computone IntelliPort Plus serial support" depends on SERIAL_NONSTANDARD @@ -387,6 +447,26 @@ config A2232 will also be built as a module. This has to be loaded before "ser_a2232". If you want to do this, answer M here. +config LEDMAN + bool "LED Manager support" + help + Enbale the LED manager driver. + +config SNAPDOG + bool "SnapGear Watchdog Support" + help + Support the SnapGear common watchdog driver. + +config FAST_TIMER + bool "Fast Timer" + help + Support the SnapGear common watchdog driver. + +config RESETSWITCH + bool "Reset switch support" + help + Support the hardware reset switch. + config SGI_SNSC bool "SGI Altix system controller communication support" depends on (IA64_SGI_SN2 || IA64_GENERIC) @@ -616,6 +696,14 @@ source "drivers/char/ipmi/Kconfig" source "drivers/char/watchdog/Kconfig" +config MCFWATCHDOG + tristate "Coldfire Watchdog" + default n + depends on COLDFIRE + help + Watchdog for Coldfire processors. /dev/watchdog is not used + for this driver. A timer-interrupt is updating the watchdog instead. + config DS1620 tristate "NetWinder thermometer support" depends on ARCH_NETWINDER @@ -709,7 +797,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH + depends on !PPC && !PARISC && !IA64 && !M68K ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -1036,6 +1124,17 @@ config MMTIMER source "drivers/char/tpm/Kconfig" +config MCF_QSPI + tristate "QSPI driver for Coldfire processors" + depends on COLDFIRE + help + Driver for Coldfire processors QSPI + +config M41T11M6 + tristate "M41T11M6 Real Time Clock (RTC) support" + help + Driver for the M41T11M6 Real Time Clock Chip. + config TELCLOCK tristate "Telecom clock driver for MPBL0010 ATCA SBC" depends on EXPERIMENTAL && X86 diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad04..27fcac73 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o obj-$(CONFIG_SGI_MBCS) += mbcs.o +obj-$(CONFIG_MCF_QSPI) += mcf_qspi.o obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_PRINTER) += lp.o @@ -90,8 +91,14 @@ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o +obj-$(CONFIG_LEDMAN) += ledman.o +obj-$(CONFIG_M41T11M6) += m41t11m6.o +obj-$(CONFIG_RESETSWITCH) += resetswitch.o obj-$(CONFIG_WATCHDOG) += watchdog/ +obj-$(CONFIG_MCFWATCHDOG) += mcfwatchdog.o +obj-$(CONFIG_SNAPDOG) += snapdog.o +obj-$(CONFIG_FAST_TIMER) += fast_timer.o obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ @@ -100,6 +107,12 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ +obj-$(CONFIG_UC71XX_GPIO) += gpio.o +obj-$(CONFIG_MOXA_LCM0) += lcm0.o +obj-$(CONFIG_MOXA_LCM1) += lcm1.o +obj-$(CONFIG_MOXA_LCM2) += lcm2.o +obj-$(CONFIG_MOXA_LCM3) += lcm3.o +obj-$(CONFIG_MOXA_KEYPAD) += keypad.o # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c diff --git a/drivers/char/altera_pio_button.c b/drivers/char/altera_pio_button.c new file mode 100644 index 00000000..28f1c025 --- /dev/null +++ b/drivers/char/altera_pio_button.c @@ -0,0 +1,280 @@ +/* + * linux/drivers/char/altera_pio_button.c + * A simple character driver that takes buttons on Nios Development + * Kit as an input device (major 62) + * + * The characters input can be '1', '2', '4' or '8' + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Written by Wentao Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUTTON_MAJOR 62 +int button_major = BUTTON_MAJOR; +int button_minor = 0; + +#define PIO_BUTTON_BASE na_button_pio +#define PIO_BUTTON_IRQ na_button_pio_irq +#define PIO_BUTTON_SIZE sizeof(np_pio) + +#define BUTTON_BUF_SIZE 100 +struct button_dev { + int count; + int head; + int tail; + char buf[BUTTON_BUF_SIZE]; + + int started; + struct cdev cdev; + wait_queue_head_t rxq; + struct semaphore mutex; +} _button_dev; + + +static void button_handle_event(void *dev_id) +{ + static int old = 0; + int status, key; + struct button_dev * dev=(struct button_dev*)dev_id; + np_pio* pio = (np_pio *)(PIO_BUTTON_BASE); + + outl(0, &pio->np_pioedgecapture); + /* read input, check 4 buttons */ + status = (~inl(&pio->np_piodata)) & 0xF; + key = status - old; + old = status; + + if (key > 0) { + down(&dev->mutex); + /* we simply discard new inputs if buffer overflows */ + if (dev->count < BUTTON_BUF_SIZE) { + dev->buf[dev->tail] = key + '0'; + dev->tail = (dev->tail+1) % BUTTON_BUF_SIZE; + dev->count++; + } + up(&dev->mutex); + + /* wake up any waiting reader */ + if (waitqueue_active(&dev->rxq)) { + wake_up(&dev->rxq); + } + } + + /* re-enable interrupts */ + outl(-1, &pio->np_piointerruptmask); +} + +static DECLARE_WORK(button_work, button_handle_event, (void*)&_button_dev); +static irqreturn_t pio_button_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + np_pio* pio = (np_pio *)PIO_BUTTON_BASE; + + if (!pio) + return IRQ_NONE; + + + /* disable interrupt */ + outl(0, &pio->np_pioedgecapture); + outl(0, &pio->np_piointerruptmask); + + /* activate the bottom half */ + schedule_work(&button_work); + + return IRQ_HANDLED; +} +static int button_start(struct button_dev *dev) +{ + np_pio *pio=(np_pio *)(PIO_BUTTON_BASE); + + outl(0, &pio->np_pioedgecapture); + outl(0, &pio->np_piodirection); + + /* register interrupt */ + if (request_irq(PIO_BUTTON_IRQ, pio_button_isr, SA_INTERRUPT, "pio_button", + (void*)(dev))) { + printk("pio_button: unable to register interrupt %d\n", PIO_BUTTON_IRQ); + return -1; + } + outl(-1, &pio->np_piointerruptmask); + + return 0; +} +/* + * Open/close . + */ +static int button_open(struct inode *inode, struct file *filp) +{ + struct button_dev *dev; + + dev = container_of(inode->i_cdev, struct button_dev, cdev); + filp->private_data = dev; + + preempt_disable(); + dev->started++; + if (dev->started!=1) { + preempt_enable(); + return 0; + } + + /* init buffon info */ + dev->count=0; + dev->head=0; + dev->tail=0; + init_waitqueue_head(&dev->rxq); + init_MUTEX(&dev->mutex); + /* init buttons */ + button_start(dev); + preempt_enable(); + + return 0; +} + +/* + */ +static int button_release(struct inode *inode, struct file *filp) +{ + np_pio *pio=(np_pio *)(PIO_BUTTON_BASE); + struct button_dev *dev = (struct button_dev*)filp->private_data; + + preempt_disable(); + dev->started--; + if (dev->started != 0) { + preempt_enable(); + return 0; + } + preempt_enable(); + + /*disable this interrupts */ + outl(0, &pio->np_piointerruptmask); + free_irq(PIO_BUTTON_IRQ, (void*)(dev)); + return 0; +} + +/* + */ +static int +button_ioctl(struct inode *inode, struct file *filp, + unsigned int command, unsigned long arg) +{ + return -EINVAL; +} + +static ssize_t button_read(struct file *filp, char *buf, + size_t count, loff_t * ppos) +{ + int i, total; + struct button_dev *dev = (struct button_dev*)filp->private_data; + + if (dev->count==0) { + DEFINE_WAIT(wait); + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + while (!signal_pending(current) && (dev->count == 0)) { + prepare_to_wait(&dev->rxq, &wait, TASK_INTERRUPTIBLE); + if (!signal_pending(current) && (dev->count == 0)) + schedule(); + finish_wait(&dev->rxq, &wait); + } + if (signal_pending(current) && (dev->count == 0)) + return -ERESTARTSYS; + } + + if (down_interruptible(&dev->mutex)) + return -ERESTARTSYS; + + /* return data */ + total = (count < dev->count) ? count : dev->count; + for (i=0; i < total; i++) { + put_user(dev->buf[dev->head], buf+i); + dev->head = (dev->head + 1) % BUTTON_BUF_SIZE; + dev->count--; + } + up(&dev->mutex); + + return total; +} + +static unsigned int button_poll(struct file *filp, poll_table *wait) +{ + struct button_dev *dev = (struct button_dev*)filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &dev->rxq, wait); + + if (dev->count > 0) + mask |= POLLIN | POLLRDNORM; /* readable */ + return mask; +} + +static struct file_operations button_fops = { + .read = button_read, + .open = button_open, + .release= button_release, + .ioctl = button_ioctl, + .poll = button_poll, + .owner = THIS_MODULE, +}; + + +static int __init button_init(void) +{ + int i; + dev_t devno; + + if (!(request_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE, "pio_button"))) + return -1; + + devno = MKDEV(button_major, button_minor); + cdev_init(&_button_dev.cdev, &button_fops); + _button_dev.cdev.owner = THIS_MODULE; + _button_dev.started = 0; + + i = register_chrdev_region(devno, 1, "pio_button"); + if (i) { + printk(KERN_NOTICE "Can't get major %d for PIO buttons", button_major); + goto error1; + } + i = cdev_add(&_button_dev.cdev, devno, 1); + if (i) { + printk(KERN_NOTICE "Error %d adding PIO buttons", i); + goto error2; + } +error2: + unregister_chrdev_region(devno, 1); +error1: + release_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE); + + return i; +} + +static void __exit button_exit(void) +{ + cdev_del(&_button_dev.cdev); + unregister_chrdev_region(MKDEV(button_major, button_minor), 1); + release_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE); +} + +module_init(button_init); +module_exit(button_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/fast_timer.c b/drivers/char/fast_timer.c new file mode 100644 index 00000000..270955f9 --- /dev/null +++ b/drivers/char/fast_timer.c @@ -0,0 +1,169 @@ +/* + * linux/drivers/char/fast_timer.c + * + * Fast timer code for general use, primarily polling network chips + * + * Copyright (c) 2004 SnapGear Inc. + * + * 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 +#include +#include +#include +#ifdef CONFIG_SYSCTL +#include +#endif + +#include + + +struct ftentry { + void (*func)(void *); + void *arg; +}; + +#define FAST_TIMER_MAX 8 +static struct ftentry fast_timer[FAST_TIMER_MAX]; +static int fast_timers = 0; +static spinlock_t fast_timer_lock; +static int fast_timer_rate; + +void fast_timer_add(void (*func)(void *arg), void *arg) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&fast_timer_lock, flags); + for (i = 0; i < fast_timers; i++) { + if (fast_timer[i].func == func && fast_timer[i].arg == arg) { + spin_unlock_irqrestore(&fast_timer_lock, flags); + printk(KERN_ERR + "fast_timer: entry already exists (0x%x, 0x%x)\n", + (unsigned int) func, (unsigned int) arg); + return; + } + } + + if (fast_timers >= FAST_TIMER_MAX) { + spin_unlock_irqrestore(&fast_timer_lock, flags); + printk(KERN_ERR "fast timer: no free slots\n"); + return; + } + + fast_timer[fast_timers].func = func; + fast_timer[fast_timers].arg = arg; + fast_timers++; + spin_unlock_irqrestore(&fast_timer_lock, flags); +} + +void fast_timer_remove(void (*func)(void *arg), void *arg) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&fast_timer_lock, flags); + for (i = 0; i < fast_timers; i++) { + if (fast_timer[i].func == func && fast_timer[i].arg == arg) { + memmove(&fast_timer[i], &fast_timer[i+1], + sizeof(struct ftentry) * (FAST_TIMER_MAX - (i+1))); + fast_timers--; + spin_unlock_irqrestore(&fast_timer_lock, flags); + return; + } + } + spin_unlock_irqrestore(&fast_timer_lock, flags); + printk(KERN_ERR "fast timer: entry does not exist (0x%x, 0x%x)\n", + (unsigned int) func, (unsigned int) arg); +} + +static void do_fast_timer(void) +{ + int i; + + for (i = 0; i < fast_timers; i++) + (*fast_timer[i].func)(fast_timer[i].arg); +} + +#include + +#ifdef CONFIG_SYSCTL +int fast_timer_sysctl(ctl_table *ctl, int write, + struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int *valp = ctl->data; + int val = *valp; + int ret; + + ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + if (write && (*valp != val)) + fast_timer_set(); + return ret; +} + +static ctl_table dev_table[] = { + {2, "fast_timer", + &fast_timer_rate, sizeof(int), 0644, NULL, &fast_timer_sysctl}, + {0} +}; + +static ctl_table root_table[] = { + {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, + {0} +}; + +static struct ctl_table_header *sysctl_header; + +static void __init init_sysctl(void) +{ + sysctl_header = register_sysctl_table(root_table, 0); +} + +static void __exit cleanup_sysctl(void) +{ + unregister_sysctl_table(sysctl_header); +} + +#else + +static inline void init_sysctl(void) +{ +} + +static inline void cleanup_sysctl(void) +{ +} + +#endif + +static int __init fast_timer_init(void) +{ + int ret; + + spin_lock_init(&fast_timer_lock); + + ret = fast_timer_setup(); + if (ret != 0) + return ret; + + init_sysctl(); + return 0; +} + +static void __exit fast_timer_exit(void) +{ + cleanup_sysctl(); + fast_timer_cleanup(); +} + +module_init(fast_timer_init); +module_exit(fast_timer_exit); +EXPORT_SYMBOL(fast_timer_add); +EXPORT_SYMBOL(fast_timer_remove); +MODULE_AUTHOR("Philip Craig "); +MODULE_DESCRIPTION("Driver for general purpose fast timer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/gpio.c b/drivers/char/gpio.c new file mode 100644 index 00000000..bf129c62 --- /dev/null +++ b/drivers/char/gpio.c @@ -0,0 +1,196 @@ +/* + * pio: 104 + * + * History: + * Date Aurhor Comment + * 12-06-2005 Victor Yu. Create it. + * 24-05-2006 Jimmy Chen. Fix it. + * 02-09-2007 Victor Yu. Porting to kernel verion 2.6.19. + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MOXA_PIO_MINOR 104 + +#define GPIO_BASE_SHIFT 10 +#define GPIO_MASK (0x3ff< MAX_PIO ) + return -EINVAL; + if ( set.mode_data == PIO_INPUT ) + mcpu_gpio_inout(1<<(set.io_number+GPIO_BASE_SHIFT), MCPU_GPIO_INPUT); + else if ( set.mode_data == PIO_OUTPUT ) + mcpu_gpio_inout(1<<(set.io_number+GPIO_BASE_SHIFT), MCPU_GPIO_OUTPUT); + else + return -EINVAL; + break; + case IOCTL_PIO_GET_MODE : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( mcpu_gpio_get_inout(1<<(set.io_number+GPIO_BASE_SHIFT)) == MCPU_GPIO_INPUT ) + set.mode_data = PIO_INPUT; + else + set.mode_data = PIO_OUTPUT; + if ( copy_to_user((struct pio_set_struct *)arg, &set, sizeof(struct pio_set_struct)) ) + return -EFAULT; + break; + case IOCTL_PIO_SET_DATA : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( set.mode_data == PIO_HIGH ) + mcpu_gpio_set(1<<(set.io_number+GPIO_BASE_SHIFT), MCPU_GPIO_HIGH); + else if ( set.mode_data == PIO_LOW ) + mcpu_gpio_set(1<<(set.io_number+GPIO_BASE_SHIFT), MCPU_GPIO_LOW); + else + return -EINVAL; + break; + case IOCTL_PIO_GET_DATA : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( mcpu_gpio_get(1<<(set.io_number+GPIO_BASE_SHIFT)) ) + set.mode_data = PIO_HIGH; + else + set.mode_data = PIO_LOW; + if ( copy_to_user((struct pio_set_struct *)arg, &set, sizeof(struct pio_set_struct)) ) + return -EFAULT; + break; + default: + return -EINVAL; + } + return 0; +} + +static int pio_open(struct inode *inode, struct file *file) +{ + if ( MINOR(inode->i_rdev) == MOXA_PIO_MINOR ) + return 0; + return -ENODEV; +} + +static int pio_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations pio_fops = { + owner:THIS_MODULE, + llseek:NULL, + ioctl:pio_ioctl, + open:pio_open, + release:pio_release, +}; +static struct miscdevice pio_dev = { + MOXA_PIO_MINOR, + "pio", + &pio_fops +}; + +#if 1 // add by Victor Yu. 03-08-2007 +extern int moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c +#endif +static void __exit pio_exit(void) +{ + misc_deregister(&pio_dev); +#if 1 // add by Victor Yu. 12-05-2007 + { + unsigned long flags; + local_irq_save(flags); + moxa_gpio_sd_used_flag = 0; + local_irq_restore(flags); + } +#endif +} + +static int __init pio_init(void) +{ + printk("Moxa CPU misc: Register PIO misc ver1.0 "); +#if 1 // add by Victor Yu. 03-08-2007 + { + unsigned long flags; + local_irq_save(flags); + if ( moxa_gpio_sd_used_flag ) { + printk("The IO has used by other device driver !\n"); + local_irq_restore(flags); + return -ENODEV; + } + moxa_gpio_sd_used_flag = 1; + local_irq_restore(flags); + } +#endif + if ( misc_register(&pio_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + + // set the CPU for GPIO + mcpu_gpio_mp_set(GPIO_MASK); + + // default set all GPIO for input + mcpu_gpio_inout(GPIO_MASK, MCPU_GPIO_OUTPUT); + + // default set all GPIO data_out high + mcpu_gpio_set(GPIO_MASK, MCPU_GPIO_HIGH); + printk("OK.\n"); + return 0; +} + +module_init(pio_init); +module_exit(pio_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/gpio.c-bak-07312007 b/drivers/char/gpio.c-bak-07312007 new file mode 100644 index 00000000..4db0b6c0 --- /dev/null +++ b/drivers/char/gpio.c-bak-07312007 @@ -0,0 +1,239 @@ +/* + * pio: 104 + * + * History: + * Date Aurhor Comment + * 12-06-2005 Victor Yu. Create it. + * 24-05-2006 Jimmy Chen. Fix it. + * 02-09-2007 Victor Yu. Porting to kernel verion 2.6.19. + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MOXA_PIO_MINOR 104 + +static spinlock_t pio_lock=SPIN_LOCK_UNLOCKED; + +// GPIO register offset on Moxa CPU +#define GPIO_DATA_OUT 0 +#define GPIO_DATA_IN 4 +#define GPIO_PIN_DIR 8 +#define GPIO_DATA_SET 0x10 +#define GPIO_DATA_CLEAR 0x14 +#define GPIO_PIN_PULL_ENABLE 0x18 +#define GPIO_PIN_PULL_TYPE 0x1C +#define GPIO_INT_ENABLE 0x20 +#define GPIO_INT_RAW_STATE 0x24 +#define GPIO_INT_MASKED_STATE 0x28 +#define GPIO_INT_MASK 0x2C +#define GPIO_INT_CLEAR 0x30 +#define GPIO_INT_TRIGGER 0x34 +#define GPIO_INT_BOTH 0x38 +#define GPIO_INT_RISE_NEG 0x3C +#define GPIO_BOUNCE_ENABLE 0x40 +#define GPIO_BOUNCE_PRE_SCALE 0x44 + +#define GPIO_BASE_SHIFT 10 +//#define GPIO_MASK (0xffff< MAX_PIO ) + return -EINVAL; + if ( set.mode_data == PIO_INPUT ) + writel(readl(&gpio_reg->pin_dir)&~(1<<(set.io_number+GPIO_BASE_SHIFT)), &gpio_reg->pin_dir); + else if ( set.mode_data == PIO_OUTPUT ) + writel(readl(&gpio_reg->pin_dir)|(1<<(set.io_number+GPIO_BASE_SHIFT)), &gpio_reg->pin_dir); + else + return -EINVAL; + break; + case IOCTL_PIO_GET_MODE : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( readl(&gpio_reg->pin_dir) & (1<<(set.io_number+GPIO_BASE_SHIFT)) ) + set.mode_data = 0; + else + set.mode_data = 1; + if ( copy_to_user((struct pio_set_struct *)arg, &set, sizeof(struct pio_set_struct)) ) + return -EFAULT; + break; + case IOCTL_PIO_SET_DATA : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( set.mode_data == PIO_HIGH ) + writel(readl(&gpio_reg->data_out)|(1<<(set.io_number+GPIO_BASE_SHIFT)), &gpio_reg->data_out); + else if ( set.mode_data == PIO_LOW ) + writel(readl(&gpio_reg->data_out)&~(1<<(set.io_number+GPIO_BASE_SHIFT)), &gpio_reg->data_out); + else + return -EINVAL; + break; + case IOCTL_PIO_GET_DATA : + if ( copy_from_user(&set, (struct pio_set_struct *)arg, sizeof(struct pio_set_struct)) ) + return -EFAULT; + if ( set.io_number < 0 || set.io_number > MAX_PIO ) + return -EINVAL; + if ( readl(&gpio_reg->data_in) & (1<<(set.io_number+GPIO_BASE_SHIFT)) ) + set.mode_data = 1; + else + set.mode_data = 0; + if ( copy_to_user((struct pio_set_struct *)arg, &set, sizeof(struct pio_set_struct)) ) + return -EFAULT; + break; + default: + return -EINVAL; + } + return 0; +} + +static int pio_open(struct inode *inode, struct file *file) +{ + if ( MINOR(inode->i_rdev) == MOXA_PIO_MINOR ) + return 0; + return -ENODEV; +} + +static int pio_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations pio_fops = { + owner:THIS_MODULE, + llseek:NULL, + ioctl:pio_ioctl, + open:pio_open, + release:pio_release, +}; +static struct miscdevice pio_dev = { + MOXA_PIO_MINOR, + "pio", + &pio_fops +}; + +static void __exit pio_exit(void) +{ + spin_lock(&pio_lock); + misc_deregister(&pio_dev); + spin_unlock(&pio_lock); +} + +#if 1 // add by Victor Yu. 03-08-2007 +extern int moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c +#endif +static int __init pio_init(void) +{ + printk("Moxa CPU misc: Register PIO misc ver1.0 "); +#if 1 // add by Victor Yu. 03-08-2007 + { + unsigned long flags; + local_irq_save(flags); + if ( moxa_gpio_sd_used_flag ) { + printk("The IO has used by other device driver !\n"); + local_irq_restore(flags); + return -ENODEV; + } + moxa_gpio_sd_used_flag = 1; + local_irq_restore(flags); + } +#endif + if ( misc_register(&pio_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + + // set the CPU for GPIO + *(volatile unsigned int *)(CPE_PMU_BASE+0x100) |= GPIO_MASK; + + // default set all GPIO for input + writel(readl(&gpio_reg->pin_dir)&~GPIO_MASK, &gpio_reg->pin_dir); + + // default set all GPIO interrupt disable + //writel(readl(&gpio_reg->int_enable)&~GPIO_MASK, &gpio_reg->int_enable); + + // default set all GPIO pin pull disable + writel(readl(&gpio_reg->pin_pull_enable)|GPIO_MASK, &gpio_reg->pin_pull_enable); + + // default set all GPIO data_out high + writel(readl(&gpio_reg->data_out)|GPIO_MASK, &gpio_reg->data_out); + printk("OK.\n"); + return 0; +} + +module_init(pio_init); +module_exit(pio_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/keypad.c b/drivers/char/keypad.c new file mode 100644 index 00000000..2fe98daf --- /dev/null +++ b/drivers/char/keypad.c @@ -0,0 +1,235 @@ +/* + * This is IVTC ODM project to use Moxa CPU for keypad device driver. + * It is from misc interface. So the device node major number is 10. + * The device node minor number is following: + * keypad: 103 + * + * There devices are mapping system memory is following: + * keypad: 0x04004000 write for out, read for in + * + * History: + * Date Aurhor Comment + * 12-05-2005 Victor Yu. Create it. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define KEYPAD_OUT_ADDR 0x84008000 +#define KEYPAD_IN_ADDR 0x84008000 +#define KEYPAD_RAW_NO 4 +#define KEYPAD_COL_NO 6 + +#define MOXA_KEYPAD_MINOR 103 + +static spinlock_t keypad_lock= SPIN_LOCK_UNLOCKED; + +// +// keypad file operation function call +// +#define IOCTL_KEYPAD_HAS_PRESS 1 +#define IOCTL_KEYPAD_GET_KEY 2 +#define IOCTL_KEYPAD_PRESS_TWICE 3 + +#define KEYPAD_BUFFER_LENGTH 32 +#define KEYPAD_BUFFER_MASK (KEYPAD_BUFFER_LENGTH-1) +#define KEYPAD_POLL_TIME (HZ/5) + +static int keypad_wptr=0, keypad_rptr=0; +static unsigned int keypad_buffer[KEYPAD_BUFFER_LENGTH]; +static unsigned int keypadold; +static struct timer_list keypadtimer; +static int keypadtimer_on=0; +static int keypad_opened=0; + +static unsigned int keypad_scan(void) +{ + unsigned int ret=0, v; + int raw, col; + + + for ( col=0; col1) + { + press_twice = 1 ; + break ; + } + } + keypad_buffer[keypad_wptr++] = v; + keypad_wptr &= KEYPAD_BUFFER_MASK; + + } + + keypadtimer.function = keypad_poll; + keypadtimer.expires = jiffies + KEYPAD_POLL_TIME; + keypadtimer_on = 1; + add_timer(&keypadtimer); + spin_unlock(&keypad_lock); +} + +static int keypad_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int v; + + switch ( cmd ) { + case IOCTL_KEYPAD_PRESS_TWICE : + if ( copy_to_user((void *)arg, &press_twice, sizeof(int)) ) + return -EFAULT; + break ; + case IOCTL_KEYPAD_HAS_PRESS : + spin_lock(&keypad_lock); +#if 1 + v = (keypad_wptr - keypad_rptr) & KEYPAD_BUFFER_MASK; +#else + if ( keypad_wptr == keypad_rptr ) + v = 0; + else + v = 1; +#endif + spin_unlock(&keypad_lock); + if ( copy_to_user((void *)arg, &v, sizeof(int)) ) + return -EFAULT; + break; + case IOCTL_KEYPAD_GET_KEY : + spin_lock(&keypad_lock); + if ( keypad_wptr == keypad_rptr ) + v = -1; + else { + v = keypad_buffer[keypad_rptr++]; + keypad_rptr &= KEYPAD_BUFFER_MASK; + } + spin_unlock(&keypad_lock); + if ( copy_to_user((void *)arg, &v, sizeof(int)) ) + return -EFAULT; + press_twice = 0 ; + break; + default: + return -EINVAL; + } + return 0; +} + +static int keypad_open(struct inode *inode, struct file *file) +{ + if ( MINOR(inode->i_rdev) != MOXA_KEYPAD_MINOR ) + return -ENODEV; + spin_lock(&keypad_lock); + if ( keypad_opened == 0 ) { + keypad_wptr = keypad_rptr = 0; + keypadold = keypad_scan(); + keypadtimer.function = keypad_poll; + keypadtimer.expires = jiffies + KEYPAD_POLL_TIME; + keypadtimer_on = 1; + add_timer(&keypadtimer); + } + keypad_opened++; + spin_unlock(&keypad_lock); + return 0; +} + +static int keypad_release(struct inode *inode, struct file *file) +{ + spin_lock(&keypad_lock); + if ( keypad_opened > 0 ) { + keypad_opened--; + if ( keypad_opened == 0 ) { + if ( keypadtimer_on ) { + del_timer(&keypadtimer); + keypadtimer_on = 0; + } + keypad_wptr = keypad_rptr = 0; + } + } + spin_unlock(&keypad_lock); + return 0; +} + +static struct file_operations keypad_fops = { + owner:THIS_MODULE, + llseek:NULL, + ioctl:keypad_ioctl, + open:keypad_open, + release:keypad_release, +}; +static struct miscdevice keypad_dev = { + MOXA_KEYPAD_MINOR, + "keypad", + &keypad_fops +}; + +static void __exit ivtc_keypad_exit(void) +{ + spin_lock(&keypad_lock); + if ( keypadtimer_on ) { + del_timer(&keypadtimer); + keypadtimer_on = 0; + } + spin_unlock(&keypad_lock); + misc_deregister(&keypad_dev); +} + +static int __init ivtc_keypad_init(void) +{ + printk("Moxa CPU misc: Register Keypad misc ver1.0 "); + if ( misc_register(&keypad_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + init_timer(&keypadtimer); + printk("OK.\n"); + + return 0; +} + +module_init(ivtc_keypad_init); +module_exit(ivtc_keypad_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lcd_16207.c b/drivers/char/lcd_16207.c new file mode 100644 index 00000000..e65d12ef --- /dev/null +++ b/drivers/char/lcd_16207.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LCD_On 1 +#define LCD_Off 2 +#define LCD_Clear 3 +#define LCD_Reset 4 +#define LCD_Cursor_Left 5 +#define LCD_Cursor_Right 6 +#define LCD_Disp_Left 7 +#define LCD_Disp_Right 8 +#define LCD_Get_Cursor 9 +#define LCD_Set_Cursor 10 +#define LCD_Home 11 +#define LCD_Read 12 +#define LCD_Write 13 +#define LCD_Cursor_Off 14 +#define LCD_Cursor_On 15 +#define LCD_Get_Cursor_Pos 16 +#define LCD_Set_Cursor_Pos 17 +#define LCD_Blink_Off 18 + +#define kLCD_IR na_lcd_16207_0 +#define kLCD_DR (na_lcd_16207_0 + 8) + +#define LCDWriteData(x) outl(x , kLCD_DR) +#define LCDWriteInst(x) outl(x , kLCD_IR) + +#define LCDReadData inl(kLCD_DR) +#define LCDReadInst inl(kLCD_IR) + + +#define Major 250 + +static int Device_Open = 0; + +static int lcd_16207_ioctl(struct inode *inode,struct file *filp, + unsigned int cmd,unsigned long arg); + +static int lcd_16207_open(struct inode *inode,struct file *filp) +{ + static int counter = 0; + if(Device_Open)return -EBUSY; + Device_Open++; + printk("You have open the device %d times\n",counter++); + return 0; +} + +static int lcd_16207_release(struct inode *inode,struct file *filp) +{ + Device_Open--; + printk("You have release the device\n"); + return 0; +} + +static int lcd_16207_ioctl(struct inode *inode,struct file *filp, + unsigned int cmd,unsigned long arg) +{ + volatile unsigned long display; + + switch (cmd) { + case LCD_On: + if (copy_from_user + (&display, (unsigned long *) arg, + sizeof(display))) + return -EFAULT; + + LCDWriteInst(display); + break; + + case LCD_Off: + if (copy_from_user + (&display, (unsigned long *) arg, + sizeof(display))) + return -EFAULT; + + LCDWriteData(display); + break; + + + default: + return -EINVAL; + } + + return 0; +} + +static struct file_operations lcd_16207_fops={ + .ioctl = lcd_16207_ioctl, + .open = lcd_16207_open, + .release = lcd_16207_release, +}; + +static int lcd_16207_init(void) +{ + int ret = register_chrdev(Major,"LCD_PIO",&lcd_16207_fops); + if(ret<0) + { + printk("Registering the device failed with %d\n",Major); + return Major; + } + printk("You have init Device %d\n",Major); + return 0; +} + +static void lcd_16207_exit(void) +{ + if(unregister_chrdev(Major,"LCD_PIO")) + printk("exit failed"); +} + +module_init(lcd_16207_init); +module_exit(lcd_16207_exit); + +MODULE_AUTHOR("Andrew Bose"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lcm0.c b/drivers/char/lcm0.c new file mode 100644 index 00000000..ec79a21b --- /dev/null +++ b/drivers/char/lcm0.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) MOXA Inc. All rights reserved. + * + * This software is distributed under the terms of the + * MOXA License. See the file COPYING-MOXA for details. + * + * This is Moxa CPU for IVTC ODM LCM moudle WG12864C device driver. + * It is from misc interface. So the device node major number is 10. + * The device node minor number is following: + * lcm : 102 + * + * There devices are mapping system memory is following: + * lcm : 0x04000000 read only, data -> LCM & control signal + * : 0x04002000 write only, LCM -> data & control signal + * + * History: + * Date Aurhor Comment + * 12-05-2005 Victor Yu. Create it. + * 09-03-2008 Victor Yu. Modify to support IVTC write byte feature. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "moxalcm.h" + +#define LCM_READ_ADDR 0x84002000 +#define LCM_WRITE_ADDR 0x84000000 + +#define MOXA_LCM_MINOR 102 + +static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED; + +// +// LCM file operation function call +// +static unsigned char fnt8x8[]={ +0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00, +0x42,0x61,0x51,0x49,0x66,0x00,0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x00,0x00, +0x18,0x14,0x52,0x7F,0x50,0x00,0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00,0x00, +0x3C,0x4A,0x49,0x49,0x32,0x00,0x00,0x00,0x03,0x01,0x79,0x05,0x03,0x00,0x00,0x00, +0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00,0x26,0x49,0x49,0x49,0x3E,0x00,0x00,0x00, +0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x41,0x7F,0x49,0x49,0x36,0x00,0x00,0x00, +0x1C,0x22,0x41,0x41,0x22,0x00,0x00,0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00,0x00, +0x41,0x7F,0x49,0x49,0x63,0x00,0x00,0x00,0x41,0x7F,0x49,0x09,0x03,0x00,0x00,0x00, +0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08,0x00,0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x00, +0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,0x5F,0x5F,0x00,0x00,0x5F,0x5F,0x00, +0x06,0x0F,0x09,0x7F,0x7F,0x01,0x7F,0x7F,0x40,0xDA,0xBF,0xA5,0xFD,0x59,0x03,0x02, +0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x80,0x94,0xB6,0xFF,0xFF,0xB6,0x94,0x80, +0x00,0x04,0x06,0x7F,0x7F,0x06,0x04,0x00,0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00, +0x08,0x08,0x08,0x2A,0x3E,0x1C,0x08,0x00,0x08,0x1C,0x3E,0x2A,0x08,0x08,0x08,0x00, +0x3C,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x08,0x1C,0x3E,0x08,0x08,0x3E,0x1C,0x08, +0x30,0x38,0x3C,0x3E,0x3E,0x3C,0x38,0x30,0x06,0x0E,0x1E,0x3E,0x3E,0x1E,0x0E,0x06, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x14,0x7F,0x14,0x14,0x14,0x7F,0x14,0x00, +0x24,0x2A,0x6B,0x2A,0x10,0x00,0x00,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00, +0x32,0x4D,0x49,0x4D,0x52,0x28,0x40,0x00,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x41,0x22,0x1C,0x00,0x00,0x00, +0x08,0x2A,0x1C,0x08,0x08,0x1C,0x2A,0x08,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00, +0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00, +0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00, +0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00, +0x62,0x51,0x51,0x49,0x49,0x46,0x00,0x00,0x22,0x41,0x41,0x49,0x49,0x36,0x00,0x00, +0x18,0x14,0x12,0x11,0x51,0x7F,0x50,0x00,0x27,0x45,0x45,0x45,0x45,0x39,0x00,0x00, +0x3C,0x4A,0x49,0x49,0x48,0x30,0x00,0x00,0x03,0x01,0x01,0x71,0x09,0x07,0x00,0x00, +0x36,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x06,0x49,0x49,0x49,0x29,0x1E,0x00,0x00, +0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0x00,0x00,0x00,0x00,0x00, +0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00, +0x00,0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x02,0x01,0x01,0x51,0x09,0x06,0x00,0x00, +0x3E,0x41,0x41,0x51,0x51,0x11,0x0E,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00, +0x41,0x7F,0x49,0x49,0x49,0x36,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x00,0x00, +0x41,0x7F,0x41,0x41,0x41,0x22,0x1C,0x00,0x7F,0x49,0x49,0x49,0x41,0x41,0x41,0x00, +0x7F,0x09,0x09,0x09,0x01,0x01,0x01,0x00,0x1C,0x22,0x41,0x41,0x41,0x51,0x32,0x00, +0x7F,0x08,0x08,0x08,0x08,0x7F,0x00,0x00,0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00, +0x30,0x40,0x40,0x40,0x41,0x3F,0x01,0x00,0x00,0x7F,0x08,0x08,0x08,0x14,0x63,0x00, +0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00,0x7F,0x02,0x04,0x08,0x04,0x02,0x7F,0x00, +0x7F,0x02,0x04,0x08,0x10,0x20,0x7F,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00, +0x00,0x7F,0x09,0x09,0x09,0x09,0x06,0x00,0x1E,0x21,0x21,0x21,0x61,0x5E,0x00,0x00, +0x7F,0x09,0x09,0x09,0x19,0x66,0x00,0x00,0x26,0x49,0x49,0x49,0x49,0x32,0x00,0x00, +0x01,0x01,0x01,0x7F,0x01,0x01,0x01,0x00,0x3F,0x40,0x40,0x40,0x40,0x3F,0x00,0x00, +0x1F,0x20,0x40,0x40,0x20,0x1F,0x00,0x00,0x7F,0x20,0x10,0x08,0x10,0x20,0x7F,0x00, +0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x07,0x08,0x78,0x08,0x07,0x00,0x00,0x00, +0x41,0x61,0x51,0x49,0x45,0x43,0x41,0x00,0x00,0x7F,0x41,0x41,0x41,0x00,0x00,0x00, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x41,0x41,0x41,0x7F,0x00,0x00,0x00, +0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x00,0x00,0x00,0x03,0x04,0x00,0x00,0x00,0x20,0x54,0x54,0x54,0x14,0x78,0x40,0x00, +0x00,0x7F,0x48,0x48,0x48,0x48,0x30,0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x00,0x00, +0x30,0x48,0x48,0x48,0x48,0x3F,0x00,0x00,0x38,0x54,0x54,0x54,0x54,0x08,0x00,0x00, +0x08,0x7E,0x09,0x09,0x01,0x02,0x00,0x00,0x98,0xA4,0xA4,0xA4,0xA4,0x78,0x00,0x00, +0x00,0x7F,0x08,0x08,0x08,0x08,0x70,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00, +0x60,0x80,0x80,0x80,0x80,0x7D,0x00,0x00,0x7F,0x10,0x10,0x10,0x28,0x44,0x00,0x00, +0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x78,0x04,0x08,0x10,0x08,0x04,0x78,0x00, +0x7C,0x04,0x04,0x04,0x04,0x78,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00, +0xFC,0x24,0x24,0x24,0x24,0x18,0x00,0x00,0x18,0x24,0x24,0x24,0x24,0xFC,0x00,0x00, +0x7C,0x08,0x04,0x04,0x04,0x08,0x00,0x00,0x48,0x54,0x54,0x54,0x54,0x24,0x00,0x00, +0x00,0x00,0x04,0x7F,0x04,0x00,0x00,0x00,0x3C,0x40,0x40,0x40,0x40,0x3C,0x00,0x00, +0x1C,0x20,0x40,0x40,0x20,0x1C,0x00,0x00,0x3C,0x40,0x20,0x10,0x20,0x40,0x3C,0x00, +0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x9C,0xA0,0xA0,0xA0,0xA0,0x7C,0x00,0x00, +0x44,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,0x00,0x08,0x08,0x36,0x41,0x41,0x00,0x00, +0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x00,0x41,0x41,0x36,0x08,0x08,0x00,0x00,0x00, +0x02,0x03,0x01,0x03,0x02,0x03,0x01,0x00,0x70,0x48,0x44,0x42,0x44,0x48,0x70,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static int lcmx, lcmy; // dots position + +// following on LCM command +#define LCM_CMD_DISPLAY_ON 0x3f +#define LCM_CMD_DISPLAY_OFF 0x3e +#define LCM_CMD_DISPLAY_START_LINE 0xc0 +#define LCM_DISPLAY_START_LINE_MASK 0x3F // 0-63 +#define LCM_CMD_SET_PAGE 0xb8 // x address +#define LCM_SET_PAGE_MASK 0x07 // x address 0-7 +#define LCM_CMD_SET_ADDRESS 0x40 // y address, from 0x40 to 0xc0 +#define LCM_SET_ADDRESS_MASK 0x3F // y address 0-63 +#define LCM_STATUS_BUSY 0x80 +#define LCM_STATUS_ON 0x20 +#define LCM_STATUS_RESET 0x10 +#define LCM_MODE_SELECT 0x05 + +// following LCM control +#define LCM_DATA (1<<8) +#define LCM_CMD 0 +#define LCM_READ (1<<9) +#define LCM_WRITE 0 +#define LCM_EBIT_ON (1<<10) +#define LCM_EBIT_OFF 0 +#define LCM_BACK_LIGHT_ON (1<<11) +#define LCM_BACK_LIGHT_OFF 0 +#define LCM_CS1 (1<<13) +#define LCM_CS2 (1<<12) +#define LCM_WRITE_ENABLE (1<<14) +#define LCM_READ_ENABLE 0 +#define LCM_DATA_MASK 0xff + +#define LCM_MAX_X_DOTS 128 +#define LCM_MAX_Y_DOTS 64 +#define LCM_HALF_X_DOTS (LCM_MAX_X_DOTS/2) +#define LCM_X_DOTS 8 +#define LCM_Y_DOTS 8 +#define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS) +#define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS) + +static unsigned char lcm_pix_buffer[LCM_MAX_Y][LCM_MAX_X_DOTS]; +static u16 lcm_ctrl_data=LCM_BACK_LIGHT_ON; +static int lcm_auto_scroll_flag=1; +static int lcm_reverse_flag=0; +typedef struct lcm_xy { + int x; // 0 - 15 + int y; // 0 - 7 +} lcm_xy_t; + +#define LCM_NOT_LOCK_INT + +static void LCM_write_cmd(u16 cmd, u16 cs) +{ +#ifndef LCM_NOT_LOCK_INT + unsigned long flags; + + save_flags(flags); + cli(); +#endif + spin_lock(&lcm_lock); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs|cmd, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|cs|cmd, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); +#ifndef LCM_NOT_LOCK_INT + restore_flags(flags); +#endif +} + +static void LCM_write_data(unsigned char data, u16 cs) +{ +#ifndef LCM_NOT_LOCK_INT + unsigned long flags; + + save_flags(flags); + cli(); +#endif + spin_lock(&lcm_lock); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs|(u16)data, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|cs|(u16)data, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); +#ifndef LCM_NOT_LOCK_INT + restore_flags(flags); +#endif +} + +static void lcm_up_one_line(void) +{ + int x, y, index, i; + + // first up one line for lcm buffer + spin_lock(&lcm_lock); + for ( y=1; y= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + spin_unlock(&lcm_lock); + return; + } + if ( lcmx < LCM_HALF_X_DOTS ) { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)lcmx, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS1); + } else { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(lcmx-LCM_HALF_X_DOTS), LCM_CS2); + LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS2); + } + index = ch * LCM_Y_DOTS; + for ( i=0; i= LCM_MAX_X_DOTS ) { + lcmx = 0; + lcmy++; + if ( lcmy >= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + } + spin_unlock(&lcm_lock); +} + +static void LCM_clear_line(void) +{ + int x, index, i; + + for ( x=0; x (LCM_MAX_X * LCM_MAX_Y) ) + count = LCM_MAX_X * LCM_MAX_Y; + if ( copy_from_user(write_buffer, buf, count) ) { + return -EFAULT; + } + for ( i=0; i= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + v = lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x]; + mask = 1 << (pos.y % LCM_Y_DOTS); + if ( cmd == IOCTL_LCM_PIX_ON ) + v |= mask; + else + v &= ~mask; + lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x] = v; + spin_unlock(&lcm_lock); + if ( pos.x < LCM_HALF_X_DOTS ) { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)pos.x, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS1); + LCM_write_data(v, LCM_CS1); + } else { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(pos.x-LCM_HALF_X_DOTS), LCM_CS2); + LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS2); + LCM_write_data(v, LCM_CS2); + } + break; + } + case IOCTL_LCM_GOTO_XY : + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y ) + return -EINVAL; + spin_lock(&lcm_lock); + lcmx = pos.x * LCM_X_DOTS; + lcmy = pos.y; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_CLS : + LCM_cls(); + break; + case IOCTL_LCM_CLEAN_LINE : + LCM_clear_line(); + break; + case IOCTL_LCM_GET_XY : + spin_lock(&lcm_lock); + pos.x = lcmx / LCM_X_DOTS; + pos.y = lcmy; + spin_unlock(&lcm_lock); + if ( copy_to_user((void *)arg, &pos,sizeof(pos)) ) + return -EFAULT; + break; + case IOCTL_LCM_BACK_LIGHT_ON : + spin_lock(&lcm_lock); + lcm_ctrl_data |= LCM_BACK_LIGHT_ON; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_BACK_LIGHT_OFF : + spin_lock(&lcm_lock); + lcm_ctrl_data &= ~LCM_BACK_LIGHT_ON; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_ON : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_OFF : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_ON : + spin_lock(&lcm_lock); + lcm_reverse_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_OFF : + spin_lock(&lcm_lock); + lcm_reverse_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_SAVE_BYTE : + if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) ) + return -EFAULT; + break; + case IOCTL_LCM_WRITE_BYTE : + { + unsigned char v, mask, cbit; + int i, x, y, ybit; + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + y = pos.y / LCM_Y_DOTS; + ybit = pos.y % LCM_Y_DOTS; + for ( i=0, x=pos.x, cbit=1; ii_rdev) == MOXA_LCM_MINOR ) + return 0; + return -ENODEV; +} + +static int lcm_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations lcm_fops = { + owner:THIS_MODULE, + llseek:NULL, + write:lcm_write, + ioctl:lcm_ioctl, + open:lcm_open, + release:lcm_release, +}; +static struct miscdevice lcm_dev = { + MOXA_LCM_MINOR, + "lcm", + &lcm_fops +}; + +#if 1 // add by Victor Yu. 04-03-2007 +extern int lcm_module_flag; +#endif +static void __exit ivtc_lcm0_exit(void) +{ + misc_deregister(&lcm_dev); + lcm_module_flag = 0; +} + +static int __init ivtc_lcm0_init(void) +{ + printk("Moxa CPU misc: Register LCM module WG12864C misc ver1.0 "); + if ( lcm_module_flag ) { + printk("fail !\nThe other type LCM module device driver has loaded.\n"); + return -ENOMEM; + } + if ( misc_register(&lcm_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + lcm_module_flag = 1; + printk("OK.\n"); + LCM_cls(); + return 0; +} + +module_init(ivtc_lcm0_init); +module_exit(ivtc_lcm0_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lcm1.c b/drivers/char/lcm1.c new file mode 100644 index 00000000..4845bffa --- /dev/null +++ b/drivers/char/lcm1.c @@ -0,0 +1,768 @@ +/* + * Copyright (C) MOXA Inc. All rights reserved. + * + * This software is distributed under the terms of the + * MOXA License. See the file COPYING-MOXA for details. + * + * This is Moxa CPU for IVTC ODM LCM moudle WG240128B device driver. + * It is from misc interface. So the device node major number is 10. + * The device node minor number is following: + * lcm : 102 + * + * There devices are mapping system memory is following: + * lcm : 0x04000000 read only, data -> LCM & control signal + * : 0x04002000 write only, LCM -> data & control signal + * + * History: + * Date Aurhor Comment + * 12-05-2005 Victor Yu. Create it. + * 01-19-2005 Jimmy Chen. Fix to work. + * 09-03-2008 Victor Yu. Modify to support IVTC write byte feature. + * + * There devices are mapping system memory is following: + * lcm : 0x84004000 read only, data -> LCM & control signal + * : 0x84000000 write only, LCM -> data & control signal + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "moxalcm.h" + +#define LCM_WRITE_ADDR 0x84000000 +#define LCM_READ_ADDR 0x84004000 + +#define MOXA_LCM_MINOR 102 + +static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED; + +// +// LCM file operation function call +// +static unsigned char fnt8x8[]={ +0x70,0x88,0x98,0xA8,0xC8,0x88,0x70,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0xF8,0x00, +0x70,0x88,0x08,0x10,0x20,0x48,0xF8,0x00,0x70,0x88,0x08,0x70,0x08,0x88,0x70,0x00, +0x10,0x30,0x50,0x90,0xF8,0x10,0x38,0x00,0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00, +0x30,0x48,0x80,0xF0,0x88,0x88,0x70,0x00,0xF8,0x88,0x10,0x20,0x20,0x20,0x20,0x00, +0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x78,0x08,0x88,0x70,0x00, +0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0xF0,0x00, +0x30,0x48,0x80,0x80,0x80,0x48,0x30,0x00,0xE0,0x90,0x88,0x88,0x88,0x90,0xE0,0x00, +0xF8,0x48,0x40,0x70,0x40,0x48,0xF8,0x00,0xF8,0x48,0x40,0x70,0x40,0x40,0xE0,0x00, +0x80,0xE0,0xF8,0xFE,0xF8,0xE0,0x80,0x00,0x02,0x0E,0x3E,0xFE,0x3E,0x0E,0x02,0x00, +0x18,0x3C,0x7E,0x18,0x18,0x7E,0x3C,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00, +0x7F,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x00,0x3E,0x63,0x38,0x6C,0x6C,0x38,0xCC,0x78, +0x00,0x00,0x00,0x00,0x7E,0x7E,0x7E,0x00,0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0xFF, +0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00, +0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00, +0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00, +0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0x7E,0x3C,0x18,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00, +0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x44,0x44,0xFE,0x44,0xFE,0x44,0x44,0x00, +0x20,0x70,0x80,0x70,0x08,0xF0,0x20,0x00,0xC2,0xC4,0x08,0x10,0x20,0x46,0x86,0x00, +0x70,0x88,0x50,0x74,0x88,0x84,0x7A,0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00, +0x08,0x10,0x20,0x20,0x20,0x10,0x08,0x00,0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00, +0x00,0x42,0x24,0xFF,0x24,0x42,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x20,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00, +0x7C,0x86,0x8A,0x92,0xA2,0xC2,0x7C,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0xF8,0x00, +0x78,0x84,0x04,0x18,0x60,0x80,0xFC,0x00,0x78,0x84,0x04,0x18,0x04,0x84,0x78,0x00, +0x1C,0x24,0x44,0x84,0xFE,0x04,0x0E,0x00,0xFC,0x80,0xF8,0x04,0x04,0x84,0x78,0x00, +0x30,0x40,0x80,0xF8,0x84,0x84,0x78,0x00,0xFC,0x84,0x04,0x08,0x10,0x10,0x10,0x00, +0x78,0x84,0x84,0x78,0x84,0x84,0x78,0x00,0x78,0x84,0x84,0x7C,0x04,0x08,0x70,0x00, +0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x20,0x40, +0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00, +0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x00,0x78,0x84,0x04,0x08,0x10,0x00,0x10,0x00, +0x7C,0x82,0x82,0x82,0x9C,0x80,0x78,0x00,0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00, +0xF8,0x44,0x44,0x78,0x44,0x44,0xF8,0x00,0x38,0x44,0x80,0x80,0x80,0x44,0x38,0x00, +0xF8,0x44,0x42,0x42,0x42,0x44,0xF8,0x00,0xFE,0x80,0x80,0xF0,0x80,0x80,0xFE,0x00, +0xFE,0x80,0x80,0xF0,0x80,0x80,0x80,0x00,0x3C,0x42,0x80,0x80,0x86,0x42,0x3C,0x00, +0x84,0x84,0x84,0xFC,0x84,0x84,0x84,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, +0x0E,0x04,0x04,0x04,0x84,0x84,0x78,0x00,0x42,0x42,0x44,0x78,0x44,0x42,0x42,0x00, +0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,0x82,0xC6,0xAA,0x92,0x82,0x82,0x82,0x00, +0x82,0xC2,0xA2,0x92,0x8A,0x86,0x82,0x00,0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x00, +0x7C,0x42,0x42,0x7C,0x40,0x40,0x40,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x0C,0x00, +0xF8,0x84,0x84,0xF8,0x88,0x84,0x84,0x00,0x78,0x84,0x80,0x78,0x04,0x84,0x78,0x00, +0xFE,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00, +0x84,0x84,0x84,0x84,0x84,0x48,0x30,0x00,0x82,0x82,0x82,0x92,0xAA,0xC6,0x82,0x00, +0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x00,0x88,0x88,0x88,0x70,0x20,0x20,0x20,0x00, +0xFE,0x04,0x08,0x10,0x20,0x40,0xFE,0x00,0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00, +0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00, +0x10,0x28,0x44,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, +0x10,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x04,0x7C,0x84,0x76,0x00, +0x40,0x40,0x40,0x7C,0x42,0x42,0x7C,0x00,0x00,0x00,0x78,0x84,0x80,0x84,0x78,0x00, +0x04,0x04,0x04,0x7C,0x84,0x84,0x78,0x00,0x00,0x00,0x78,0x84,0xF8,0x80,0x78,0x00, +0x38,0x44,0x40,0xF0,0x40,0x40,0x40,0x00,0x00,0x00,0x78,0x84,0x84,0x7C,0x04,0xF8, +0x40,0x40,0x40,0x7C,0x42,0x42,0x42,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x00, +0x04,0x00,0x04,0x04,0x04,0x84,0x84,0x78,0x80,0x80,0x84,0x88,0xF0,0x88,0x84,0x00, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x44,0xAA,0x92,0x82,0x82,0x00, +0x00,0x00,0xF8,0x84,0x84,0x84,0x84,0x00,0x00,0x00,0x78,0x84,0x84,0x84,0x78,0x00, +0x00,0x00,0xF8,0x84,0x84,0xF8,0x80,0x80,0x00,0x00,0x7C,0x84,0x84,0x7C,0x04,0x04, +0x00,0x00,0xB8,0xC4,0x80,0x80,0x80,0x00,0x00,0x00,0x7C,0x80,0x78,0x04,0xF8,0x00, +0x10,0x10,0x38,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x78,0x00, +0x00,0x00,0x84,0x84,0x84,0x48,0x30,0x00,0x00,0x00,0x82,0x82,0x92,0xAA,0x44,0x00, +0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x00,0x84,0x84,0x84,0x7C,0x04,0xF8, +0x00,0x00,0xFC,0x08,0x10,0x20,0xFC,0x00,0x0C,0x10,0x10,0x60,0x10,0x10,0x0C,0x00, +0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,0xC0,0x20,0x20,0x18,0x20,0x20,0xC0,0x00, +0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x28,0x44,0x82,0x82,0xFE,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static int lcmx, lcmy; // dots position + +// following on LCM command +#define LCM_CMD_SET_CUR_POINT 0x21 // set cursor pointer +#define LCM_CMD_SET_OFF_REG 0x22 // set offset register +#define LCM_CMD_SET_ADDR_POINT 0x24 // set address pointer +#define LCM_CMD_SET_T_H_ADDR 0x40 // set text home address +#define LCM_CMD_SET_T_AREA 0x41 // set text area +#define LCM_CMD_SET_G_H_ADDR 0x42 // set graphic home address +#define LCM_CMD_SET_G_AREA 0x43 // set graphic area +#define LCM_CMD_OR_MODE 0x80 // OR mode +#define LCM_CMD_EXOR_MODE 0x81 // EXOR mode +#define LCM_CMD_AND_MODE 0x83 // AND mode +#define LCM_CMD_T_ATTR 0x84 // text attribute mode +#define LCM_CMD_INT_CG_ROM 0x85 // internal CG ROM mode +#define LCM_CMD_EXT_CG_RAM 0x88 // external CG RAM mode +#define LCM_CMD_DISPLAY_OFF 0x90 // display off +#define LCM_CMD_CO_BF 0x92 // cursor on, blink off +#define LCM_CMD_CO_BO 0x93 // cursor on, blink on +#define LCM_CMD_TO_GF 0x94 // text on, graphic off +#define LCM_CMD_TF_GO 0x98 // text off, graphic on +#define LCM_CMD_TO_GO 0x9c // text on, graphic on +#define LCM_CMD_CUR_1 0xa0 // 1-line cursor +#define LCM_CMD_CUR_2 0xa1 // 2-line cursor +#define LCM_CMD_CUR_3 0xa2 // 3-line cursor +#define LCM_CMD_CUR_4 0xa3 // 4-line cursor +#define LCM_CMD_CUR_5 0xa4 // 5-line cursor +#define LCM_CMD_CUR_6 0xa5 // 6-line cursor +#define LCM_CMD_CUR_7 0xa6 // 7-line cursor +#define LCM_CMD_CUR_8 0xa7 // 8-line cursor +#define LCM_CMD_DATA_AW 0xb0 // set data auto write +#define LCM_CMD_DATA_AR 0xb1 // set data auto read +#define LCM_CMD_AUTO_RESET 0xb2 // auto reset +#define LCM_CMD_DW_INC 0xc0 // data write and increment ADP +#define LCM_CMD_DR_INC 0xc1 // data read and increment ADP +#define LCM_CMD_DW_DEC 0xc2 // data write and decrement ADP +#define LCM_CMD_DR_DEC 0xc3 // data read and decrement ADP +#define LCM_CMD_DW_NON 0xc4 // data write and nonvariable ADP +#define LCM_CMD_DR_NON 0xc5 // data read and nonvariable ADP +#define LCM_CMD_SCR_PEEk 0xe0 // screen peek +#define LCM_CMD_SCR_COPY 0xe8 // screen copy +#define LCM_CMD_BIT_RESET 0xf0 // bit reset +#define LCM_CMD_BIT_SET 0xf9 // bit set +#define LCM_CMD_BIT_0 0xf8 // bit 0 +#define LCM_CMD_BIT_1 0xf9 // bit 1 +#define LCM_CMD_BIT_2 0xfa // bit 2 +#define LCM_CMD_BIT_3 0xfb // bit 3 +#define LCM_CMD_BIT_4 0xfc // bit 4 +#define LCM_CMD_BIT_5 0xfd // bit 5 +#define LCM_CMD_BIT_6 0xfe // bit 6 +#define LCM_CMD_BIT_7 0xff // bit 7 + +// following status +#define LCM_CMD_EXEC_CAP (1<<0) // check command execution cap. +#define LCM_DATA_RW_CAP (1<<1) // check data read/write cap. +#define LCM_AUTO_RD_CAP (1<<2) // check auto mode data read cap. +#define LCM_AUTO_WD_CAP (1<<3) // check auto mode data write cap. +#define LCM_CTRL_OP_CAP (1<<5) // check controller operation cap. +#define LCM_ERR_FLAG (1<<6) // error flag +#define LCM_BLINK_CON (1<<7) // check the blink condition + +// following LCM control for CPU +#define CD_0 0 +#define CD_1 (1<<8) // when write +#define CE_1 (1<<10) +#define CE_0 0 +#define RD_1 (1<<9) // data write +#define RD_0 0 +#define WR_1 (1<<12) // data read +#define WR_0 0 +#define LCM_STATUS_READ (1<<8) // when read +#define LCM_READ_ENABLE (1<<14) +#define LCM_WRITE_ENABLE 0 +#define LCM_DATA_MASK 0xff + +//DATA AUTO READ/WRITE +#define LCM_DATA_ATOW 0xB0 //Set Data Auto Write +#define LCM_DATA_ATOR 0xB1 //Set Data Auto Read +#define LCM_AUTO_RESET 0xB2 //Auto Reset + +#define LCM_MAX_X_DOTS 240 +#define LCM_MAX_Y_DOTS 128 +#define LCM_HALF_X_DOTS (LCM_MAX_X_DOTS/2) +#define LCM_X_DOTS 8 +#define LCM_Y_DOTS 8 +#define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS) +#define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS) +#define LCM_ADDRESS_X_Y(x,y) ((y)*LCM_MAX_X + x) + +static unsigned char lcm_pix_buffer[LCM_MAX_X_DOTS][LCM_MAX_Y_DOTS]; +static int lcm_auto_scroll_flag=1; +static int lcm_reverse_flag=0; +typedef struct lcm_xy { + int x; // 0 - 15 + int y; // 0 - 7 +} lcm_xy_t; + +#define LCM_NOT_LOCK_INT +static inline int LCM_check_status(u16 check_status) +{ +#define LCM_RETRY_COUNT 10 + int i, ret = 0; + u16 status ; + + for ( i=0; i>8)&0xff); + index = x * LCM_X_DOTS; + for ( i=0; i= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + spin_unlock(&lcm_lock); + return; + } + addr = ((lcmy*8)*0x1e) + (lcmx/LCM_X_DOTS) ; + //addr = LCM_ADDRESS_X_Y(lcmx, lcmy); + LCM_two_arguments_cmd(LCM_CMD_SET_ADDR_POINT,(u16)addr&0xFF,(u16)(addr>>8)); + + index = ch * LCM_X_DOTS; + for ( i=0; i>8) ; + LCM_one_argument_cmd(LCM_CMD_DW_INC,(u16)fnt8x8[index]); + } + spin_lock(&lcm_lock); + if ( lcmx >= LCM_MAX_X_DOTS ) { + lcmx = 0; + lcmy++; + if ( lcmy >= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + } + spin_unlock(&lcm_lock); +} + +static void LCM_clear_line(void) +{ + int x, index, i, addr; + + for ( x=0; x>8)&0xff); + index = x * LCM_X_DOTS; + for ( i=0; i>8) ; + //LCM_no_argument_cmd(LCM_DATA_ATOW) ; + while(size--) + LCM_one_argument_cmd(LCM_CMD_DW_INC,(*string++)-' '); + //LCM_no_argument_cmd(LCM_AUTO_RESET) ; +} +static void LCM_write_graph(u16 column,u16 data) +{ + LCM_two_arguments_cmd(LCM_CMD_SET_ADDR_POINT,column&0xFF,column>>8) ; + //LCM_no_argument_cmd(LCM_DATA_ATOW) ; + LCM_one_argument_cmd(LCM_CMD_DW_INC,data); + //LCM_no_argument_cmd(LCM_AUTO_RESET) ; +} +#endif + +#define T_AREA_SIZE 0x1e +#define G_AREA_SIZE 0x1e +#define TEST_STRING0 "Hello world !! Phone: 02-89191" +#define TEST_STRING1 "230 # 235" + +/* + * I don't know why cannot malloc memory from kernel. + * 03-10-2004 Victor Yu. + */ +#define USE_WRITE_BUFFER +static ssize_t lcm_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) +{ +#ifdef USE_WRITE_BUFFER + char write_buffer[LCM_MAX_X * LCM_MAX_Y]; +#else + char *ptr; +#endif + int i; + + if ( count == 0 ) + return 0; +#ifdef USE_WRITE_BUFFER + if ( count > (LCM_MAX_X * LCM_MAX_Y) ) + count = LCM_MAX_X * LCM_MAX_Y; + if ( copy_from_user(write_buffer, buf, count) ) { + return -EFAULT; + } + for ( i=0; i= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + v = lcm_pix_buffer[pos.y][pos.x/LCM_X_DOTS]; + mask = 0x80 >> (pos.x % 8); + if ( cmd == IOCTL_LCM_PIX_ON ) + v |= mask; + else + v &= ~mask; + lcm_pix_buffer[pos.y][pos.x/LCM_X_DOTS] = v; + spin_unlock(&lcm_lock); + addr = ((pos.y)*0x1e) + (pos.x/LCM_X_DOTS) ; + LCM_two_arguments_cmd(LCM_CMD_SET_ADDR_POINT,(u16)(addr&0xFF),(u16)(addr>>8)); + LCM_one_argument_cmd(LCM_CMD_DW_INC,(u16)v); + break; + } + case IOCTL_LCM_GOTO_XY : + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y ) + return -EINVAL; + spin_lock(&lcm_lock); + lcmx = pos.x * LCM_X_DOTS; + lcmy = pos.y; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_CLS : + LCM_clear(); + break; + case IOCTL_LCM_CLEAN_LINE : + LCM_clear_line(); + break; + case IOCTL_LCM_GET_XY : + spin_lock(&lcm_lock); + pos.x = lcmx / LCM_X_DOTS; + pos.y = lcmy; + spin_unlock(&lcm_lock); + if ( copy_to_user((void *)arg, &pos,sizeof(pos)) ) + return -EFAULT; + break; + case IOCTL_LCM_BACK_LIGHT_ON : + case IOCTL_LCM_BACK_LIGHT_OFF : + break; + case IOCTL_LCM_AUTO_SCROLL_ON : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_OFF : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_ON : + spin_lock(&lcm_lock); + lcm_reverse_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_OFF : + spin_lock(&lcm_lock); + lcm_reverse_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_SAVE_BYTE : + if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) ) + return -EFAULT; + break; + case IOCTL_LCM_WRITE_BYTE : + { + u16 addr; + + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + lcm_pix_buffer[pos.y][pos.x/LCM_X_DOTS] = user_data; + spin_unlock(&lcm_lock); + addr = ((pos.y)*0x1e) + (pos.x/LCM_X_DOTS) ; + LCM_two_arguments_cmd(LCM_CMD_SET_ADDR_POINT,(u16)(addr&0xFF),(u16)(addr>>8)); + LCM_one_argument_cmd(LCM_CMD_DW_INC,(u16)user_data); + break; + } + case IOCTL_LCM_DISPLAY_OFF : + LCM_no_argument_cmd(LCM_CMD_DISPLAY_OFF); + break; + case IOCTL_LCM_DISPLAY_ON : + LCM_no_argument_cmd(LCM_CMD_TF_GO); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int lcm_open(struct inode *inode, struct file *file) +{ + if ( MINOR(inode->i_rdev) == MOXA_LCM_MINOR ) + return 0; + return -ENODEV; +} + +static int lcm_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations lcm_fops = { + owner:THIS_MODULE, + llseek:NULL, + write:lcm_write, + ioctl:lcm_ioctl, + open:lcm_open, + release:lcm_release, +}; +static struct miscdevice lcm_dev = { + MOXA_LCM_MINOR, + "lcm", + &lcm_fops +}; + +#if 1 // add by Victor Yu. 04-03-2007 +extern int lcm_module_flag; +#endif +static void __exit ivtc_lcm1_exit(void) +{ + misc_deregister(&lcm_dev); + lcm_module_flag = 0; +} + +static int __init ivtc_lcm1_init(void) +{ + + printk("Moxa CPU misc: Register LCM module WG240128B misc ver1.0 "); + if ( lcm_module_flag ) { + printk("fail !\nThe other type LCM module device driver has loaded.\n"); + return -ENOMEM; + } + if ( misc_register(&lcm_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + lcm_module_flag = 1; + printk("OK.\n"); + + /* text address & area + jimmy_chen@moxa.com.tw:turn down text area, we use own font + LCM_two_arguments_cmd(LCM_CMD_SET_T_H_ADDR,0,0) ; + LCM_two_arguments_cmd(LCM_CMD_SET_T_AREA,T_AREA_SIZE,0) ; + */ + /* graphic address & area */ + LCM_two_arguments_cmd(LCM_CMD_SET_G_H_ADDR,0,0) ; + LCM_two_arguments_cmd(LCM_CMD_SET_G_AREA,G_AREA_SIZE,0) ; + /* set or mode */ + LCM_no_argument_cmd(LCM_CMD_OR_MODE) ; + /* reset register off set is use by text area */ + LCM_two_arguments_cmd(LCM_CMD_SET_OFF_REG,0,0) ; + /* set text off graphic on mode */ + LCM_no_argument_cmd(LCM_CMD_TF_GO) ; + /* clear screen */ + LCM_clear() ; + + /* + LCM_write_graph(0x00,fnt8x8[16]) ; + LCM_write_graph(0x1e*1,fnt8x8[17]) ; + LCM_write_graph(0x1e*2,fnt8x8[18]) ; + LCM_write_graph(0x1e*3,fnt8x8[19]) ; + LCM_write_graph(0x1e*4,fnt8x8[20]) ; + LCM_write_graph(0x1e*5,fnt8x8[21]) ; + LCM_write_graph(0x1e*6,fnt8x8[22]) ; + LCM_write_graph(0x1e*7,fnt8x8[23]) ; + */ + + return 0; +} + +module_init(ivtc_lcm1_init); +module_exit(ivtc_lcm1_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lcm2.c b/drivers/char/lcm2.c new file mode 100644 index 00000000..dc7fc269 --- /dev/null +++ b/drivers/char/lcm2.c @@ -0,0 +1,729 @@ +/* + * Copyright (C) MOXA Inc. All rights reserved. + * + * This software is distributed under the terms of the + * MOXA License. See the file COPYING-MOXA for details. + * + * This is Moxa CPU for IVTC ODM LCM moudle WG12232C device driver. + * It is from misc interface. So the device node major number is 10. + * The device node minor number is following: + * lcm : 102 + * + * There devices are mapping system memory is following: + * lcm : 0x84002000 read only, data -> LCM & control signal + * : 0x84000000 write only, LCM -> data & control signal + * + * History: + * Date Aurhor Comment + * 12-05-2005 Victor Yu. Create it. + * 05-11-2006 Jimmy Chen. Fix to work. + * 09-03-2008 Victor Yu. Modify to support IVTC write byte feature. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "moxalcm.h" + +#define LCM_READ_ADDR 0x84002000 +#define LCM_WRITE_ADDR 0x84000000 + +#define MOXA_LCM_MINOR 102 + +static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED; + +// +// LCM file operation function call +// +static unsigned char fnt8x8[]={ +0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00, +0x42,0x61,0x51,0x49,0x66,0x00,0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x00,0x00, +0x18,0x14,0x52,0x7F,0x50,0x00,0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00,0x00, +0x3C,0x4A,0x49,0x49,0x32,0x00,0x00,0x00,0x03,0x01,0x79,0x05,0x03,0x00,0x00,0x00, +0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00,0x26,0x49,0x49,0x49,0x3E,0x00,0x00,0x00, +0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x41,0x7F,0x49,0x49,0x36,0x00,0x00,0x00, +0x1C,0x22,0x41,0x41,0x22,0x00,0x00,0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00,0x00, +0x41,0x7F,0x49,0x49,0x63,0x00,0x00,0x00,0x41,0x7F,0x49,0x09,0x03,0x00,0x00,0x00, +0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08,0x00,0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x00, +0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,0x5F,0x5F,0x00,0x00,0x5F,0x5F,0x00, +0x06,0x0F,0x09,0x7F,0x7F,0x01,0x7F,0x7F,0x40,0xDA,0xBF,0xA5,0xFD,0x59,0x03,0x02, +0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x80,0x94,0xB6,0xFF,0xFF,0xB6,0x94,0x80, +0x00,0x04,0x06,0x7F,0x7F,0x06,0x04,0x00,0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00, +0x08,0x08,0x08,0x2A,0x3E,0x1C,0x08,0x00,0x08,0x1C,0x3E,0x2A,0x08,0x08,0x08,0x00, +0x3C,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x08,0x1C,0x3E,0x08,0x08,0x3E,0x1C,0x08, +0x30,0x38,0x3C,0x3E,0x3E,0x3C,0x38,0x30,0x06,0x0E,0x1E,0x3E,0x3E,0x1E,0x0E,0x06, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x14,0x7F,0x14,0x14,0x14,0x7F,0x14,0x00, +0x24,0x2A,0x6B,0x2A,0x10,0x00,0x00,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00, +0x32,0x4D,0x49,0x4D,0x52,0x28,0x40,0x00,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x41,0x22,0x1C,0x00,0x00,0x00, +0x08,0x2A,0x1C,0x08,0x08,0x1C,0x2A,0x08,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00, +0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00, +0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00, +0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00, +0x62,0x51,0x51,0x49,0x49,0x46,0x00,0x00,0x22,0x41,0x41,0x49,0x49,0x36,0x00,0x00, +0x18,0x14,0x12,0x11,0x51,0x7F,0x50,0x00,0x27,0x45,0x45,0x45,0x45,0x39,0x00,0x00, +0x3C,0x4A,0x49,0x49,0x48,0x30,0x00,0x00,0x03,0x01,0x01,0x71,0x09,0x07,0x00,0x00, +0x36,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x06,0x49,0x49,0x49,0x29,0x1E,0x00,0x00, +0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0x00,0x00,0x00,0x00,0x00, +0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00, +0x00,0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x02,0x01,0x01,0x51,0x09,0x06,0x00,0x00, +0x3E,0x41,0x41,0x51,0x51,0x11,0x0E,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00, +0x41,0x7F,0x49,0x49,0x49,0x36,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x00,0x00, +0x41,0x7F,0x41,0x41,0x41,0x22,0x1C,0x00,0x7F,0x49,0x49,0x49,0x41,0x41,0x41,0x00, +0x7F,0x09,0x09,0x09,0x01,0x01,0x01,0x00,0x1C,0x22,0x41,0x41,0x41,0x51,0x32,0x00, +0x7F,0x08,0x08,0x08,0x08,0x7F,0x00,0x00,0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00, +0x30,0x40,0x40,0x40,0x41,0x3F,0x01,0x00,0x00,0x7F,0x08,0x08,0x08,0x14,0x63,0x00, +0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00,0x7F,0x02,0x04,0x08,0x04,0x02,0x7F,0x00, +0x7F,0x02,0x04,0x08,0x10,0x20,0x7F,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00, +0x00,0x7F,0x09,0x09,0x09,0x09,0x06,0x00,0x1E,0x21,0x21,0x21,0x61,0x5E,0x00,0x00, +0x7F,0x09,0x09,0x09,0x19,0x66,0x00,0x00,0x26,0x49,0x49,0x49,0x49,0x32,0x00,0x00, +0x01,0x01,0x01,0x7F,0x01,0x01,0x01,0x00,0x3F,0x40,0x40,0x40,0x40,0x3F,0x00,0x00, +0x1F,0x20,0x40,0x40,0x20,0x1F,0x00,0x00,0x7F,0x20,0x10,0x08,0x10,0x20,0x7F,0x00, +0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x07,0x08,0x78,0x08,0x07,0x00,0x00,0x00, +0x41,0x61,0x51,0x49,0x45,0x43,0x41,0x00,0x00,0x7F,0x41,0x41,0x41,0x00,0x00,0x00, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x41,0x41,0x41,0x7F,0x00,0x00,0x00, +0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +0x00,0x00,0x00,0x03,0x04,0x00,0x00,0x00,0x20,0x54,0x54,0x54,0x14,0x78,0x40,0x00, +0x00,0x7F,0x48,0x48,0x48,0x48,0x30,0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x00,0x00, +0x30,0x48,0x48,0x48,0x48,0x3F,0x00,0x00,0x38,0x54,0x54,0x54,0x54,0x08,0x00,0x00, +0x08,0x7E,0x09,0x09,0x01,0x02,0x00,0x00,0x98,0xA4,0xA4,0xA4,0xA4,0x78,0x00,0x00, +0x00,0x7F,0x08,0x08,0x08,0x08,0x70,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00, +0x60,0x80,0x80,0x80,0x80,0x7D,0x00,0x00,0x7F,0x10,0x10,0x10,0x28,0x44,0x00,0x00, +0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x78,0x04,0x08,0x10,0x08,0x04,0x78,0x00, +0x7C,0x04,0x04,0x04,0x04,0x78,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00, +0xFC,0x24,0x24,0x24,0x24,0x18,0x00,0x00,0x18,0x24,0x24,0x24,0x24,0xFC,0x00,0x00, +0x7C,0x08,0x04,0x04,0x04,0x08,0x00,0x00,0x48,0x54,0x54,0x54,0x54,0x24,0x00,0x00, +0x00,0x00,0x04,0x7F,0x04,0x00,0x00,0x00,0x3C,0x40,0x40,0x40,0x40,0x3C,0x00,0x00, +0x1C,0x20,0x40,0x40,0x20,0x1C,0x00,0x00,0x3C,0x40,0x20,0x10,0x20,0x40,0x3C,0x00, +0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x9C,0xA0,0xA0,0xA0,0xA0,0x7C,0x00,0x00, +0x44,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,0x00,0x08,0x08,0x36,0x41,0x41,0x00,0x00, +0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x00,0x41,0x41,0x36,0x08,0x08,0x00,0x00,0x00, +0x02,0x03,0x01,0x03,0x02,0x03,0x01,0x00,0x70,0x48,0x44,0x42,0x44,0x48,0x70,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static int lcmx, lcmy; // dots position + +// following on LCM command +#define LCM_CMD_DISPLAY_ON 0xaf +#define LCM_CMD_DISPLAY_OFF 0xae +#define LCM_CMD_DISPLAY_START_LINE 0xc0 +#define LCM_DISPLAY_START_LINE_MASK 0x1F // 0-31 +#define LCM_CMD_SET_PAGE 0xb8 // x address +#define LCM_SET_PAGE_MASK 0x03 // x address 0-3 +#define LCM_CMD_SET_ADDRESS 0x00 // y address, from 0x40 to 0xc0 +#define LCM_SET_ADDRESS_MASK 0x7F // y address 0-79 +#define LCM_STATUS_BUSY 0x80 +#define LCM_STATUS_ON 0x20 +#define LCM_STATUS_RESET 0x10 +#define LCM_MODE_SELECT 0x05 + +// following LCM control +#define LCM_DATA (1<<8) +#define LCM_CMD 0 +#define LCM_READ (1<<9) +#define LCM_WRITE 0 +#define LCM_EBIT_ON (1<<10) +#define LCM_EBIT_OFF 0 +#define LCM_BACK_LIGHT_OFF (1<<11) +#define LCM_BACK_LIGHT_ON 0 +#define LCM_CS1 (1<<13) +#define LCM_CS2 (1<<12) +#define LCM_WRITE_ENABLE (1<<14) +#define LCM_READ_ENABLE 0 +#define LCM_DATA_MASK 0xff +#define LCM_ADC 0xa0 +#define LCM_ADC_MASK 0x1 + +//#define LCM_MAX_X_DOTS 120 +#define LCM_MAX_X_DOTS 120 +#define LCM_MAX_Y_DOTS 32 +#define LCM_HALF_X_DOTS 61 +//#define LCM_HALF_X_DOTS (LCM_MAX_X_DOTS/2) +#define LCM_X_DOTS 8 +#define LCM_Y_DOTS 8 +#define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS) +#define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS) + +static unsigned char lcm_pix_buffer[LCM_MAX_Y][LCM_MAX_X_DOTS]; +static u16 lcm_ctrl_data=LCM_BACK_LIGHT_ON; +static int lcm_auto_scroll_flag=1; +static int lcm_reverse_flag=0; +typedef struct lcm_xy { + int x; // 0 - 15 + int y; // 0 - 7 +} lcm_xy_t; + +#define LCM_NOT_LOCK_INT + +static void LCM_write_cmd(u16 cmd, u16 cs) +{ +#ifndef LCM_NOT_LOCK_INT + unsigned long flags; + + save_flags(flags); + cli(); +#endif + spin_lock(&lcm_lock); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs|cmd, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|cs|cmd, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); +#ifndef LCM_NOT_LOCK_INT + restore_flags(flags); +#endif +} + +static void LCM_write_data(unsigned char data, u16 cs) +{ +#ifndef LCM_NOT_LOCK_INT + unsigned long flags; + + save_flags(flags); + cli(); +#endif + spin_lock(&lcm_lock); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs|(u16)data, LCM_WRITE_ADDR); + udelay(20) ; + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|cs|(u16)data, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); +#ifndef LCM_NOT_LOCK_INT + restore_flags(flags); +#endif +} + +static void lcm_up_one_line(void) +{ + int x, y, index, i; + + // first up one line for lcm buffer + spin_lock(&lcm_lock); + for ( y=1; y= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + spin_unlock(&lcm_lock); + return; + } +#if 0 + if ( lcmx < LCM_HALF_X_DOTS ) { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)lcmx, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS1); + } else { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(lcmx-LCM_HALF_X_DOTS), LCM_CS2); + LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS2); + } +#endif + index = ch * LCM_Y_DOTS; + for ( i=0; i= LCM_MAX_X_DOTS ) { + lcmx = 0; + lcmy++; + if ( lcmy >= LCM_MAX_Y ) { + if ( lcm_auto_scroll_flag ) { + lcmy = LCM_MAX_Y - 1; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + } + spin_unlock(&lcm_lock); +} + +static void LCM_clear_line(void) +{ + int x, index, i; + + for ( x=0; x (LCM_MAX_X * LCM_MAX_Y) ) + count = LCM_MAX_X * LCM_MAX_Y; + if ( copy_from_user(write_buffer, buf, count) ) { + return -EFAULT; + } + for ( i=0; i= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + v = lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x]; + mask = 1 << (pos.y % LCM_Y_DOTS); + if ( cmd == IOCTL_LCM_PIX_ON ) + v |= mask; + else + v &= ~mask; + lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x] = v; + spin_unlock(&lcm_lock); + if ( pos.x < LCM_HALF_X_DOTS ) { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)pos.x, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS1); + LCM_write_data(v, LCM_CS1); + } else { + LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(pos.x-LCM_HALF_X_DOTS), LCM_CS2); + LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS2); + LCM_write_data(v, LCM_CS2); + } + break; + } + case IOCTL_LCM_GOTO_XY : + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y ) + return -EINVAL; + spin_lock(&lcm_lock); + lcmx = pos.x * LCM_X_DOTS; + lcmy = pos.y; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_CLS : + LCM_cls(); + break; + case IOCTL_LCM_CLEAN_LINE : + LCM_clear_line(); + break; + case IOCTL_LCM_GET_XY : + spin_lock(&lcm_lock); + pos.x = lcmx / LCM_X_DOTS; + pos.y = lcmy; + spin_unlock(&lcm_lock); + if ( copy_to_user((void *)arg, &pos,sizeof(pos)) ) + return -EFAULT; + break; + case IOCTL_LCM_BACK_LIGHT_ON : + spin_lock(&lcm_lock); + lcm_ctrl_data |= LCM_BACK_LIGHT_ON; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_BACK_LIGHT_OFF : + spin_lock(&lcm_lock); + lcm_ctrl_data &= ~LCM_BACK_LIGHT_ON; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_ON : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_OFF : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_ON : + spin_lock(&lcm_lock); + lcm_reverse_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_OFF : + spin_lock(&lcm_lock); + lcm_reverse_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_SAVE_BYTE : + if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) ) + return -EFAULT; + break; + case IOCTL_LCM_WRITE_BYTE : + { + unsigned char v, mask, cbit; + int i, x, y, ybit; + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + y = pos.y / LCM_Y_DOTS; + ybit = pos.y % LCM_Y_DOTS; + for ( i=0, x=pos.x, cbit=1; ii_rdev) == MOXA_LCM_MINOR ) + return 0; + return -ENODEV; +} + +static int lcm_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations lcm_fops = { + owner:THIS_MODULE, + llseek:NULL, + write:lcm_write, + ioctl:lcm_ioctl, + open:lcm_open, + release:lcm_release, +}; +static struct miscdevice lcm_dev = { + MOXA_LCM_MINOR, + "lcm", + &lcm_fops +}; + +#if 1 // add by Victor Yu. 04-03-2007 +extern int lcm_module_flag; +#endif +static void __exit ivtc_lcm2_exit(void) +{ + misc_deregister(&lcm_dev); + lcm_module_flag = 0; +} + +static int __init ivtc_lcm2_init(void) +{ + printk("Moxa CPU misc: Register LCM module WG12232C misc ver1.0 "); + if ( lcm_module_flag ) { + printk("fail !\nThe other type LCM module device driver has loaded.\n"); + return -ENOMEM; + } + if ( misc_register(&lcm_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + lcm_module_flag = 1; + printk("OK.\n"); + LCM_cls() ; + + LCM_write_cmd(LCM_CMD_DISPLAY_START_LINE|(0x07&LCM_DISPLAY_START_LINE_MASK),LCM_CS1|LCM_CS2) ; + LCM_write_cmd(LCM_ADC|(0&LCM_ADC_MASK),LCM_CS1|LCM_CS2) ; +#if 0 + LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS1); + LCM_write_cmd(LCM_CMD_SET_PAGE | (2 & LCM_SET_PAGE_MASK), LCM_CS1); + LCM_write_data(0xaa, LCM_CS1); + LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS1); +#endif + return 0; +} + +module_init(ivtc_lcm2_init); +module_exit(ivtc_lcm2_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/lcm3.c b/drivers/char/lcm3.c new file mode 100644 index 00000000..0313b1e7 --- /dev/null +++ b/drivers/char/lcm3.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) MOXA Inc. All rights reserved. + * + * This software is distributed under the terms of the + * MOXA License. See the file COPYING-MOXA for details. + * + * This is Moxa CPU for IVTC ODM LCM moudle WG16080A device driver. + * It is from misc interface. So the device node major number is 10. + * The device node minor number is following: + * lcm : 102 + * + * There devices are mapping system memory is following: + * lcm : 0x04000000 read only, data -> LCM & control signal + * : 0x04002000 write only, LCM -> data & control signal + * + * History: + * Date Aurhor Comment + * 09-02-2008 Victor Yu. Create it. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "moxalcm.h" + +#define LCM_READ_ADDR 0x84002000 +#define LCM_WRITE_ADDR 0x84000000 + +#define MOXA_LCM_MINOR 102 + +static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED; + +// +// LCM file operation function call +// +static unsigned char fnt8x8[]={ +0x0E,0x11,0x19,0x15,0x13,0x11,0x0E,0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x1F,0x00, +0x0E,0x11,0x10,0x08,0x04,0x12,0x1F,0x00,0x0E,0x11,0x10,0x0E,0x10,0x11,0x0E,0x00, +0x08,0x0C,0x0A,0x09,0x1F,0x08,0x1C,0x00,0x1F,0x01,0x0F,0x10,0x10,0x11,0x0E,0x00, +0x0C,0x12,0x01,0x0F,0x11,0x11,0x0E,0x00,0x1F,0x11,0x08,0x04,0x04,0x04,0x04,0x00, +0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00,0x0E,0x11,0x11,0x1E,0x10,0x11,0x0E,0x00, +0x04,0x0A,0x11,0x11,0x1F,0x11,0x11,0x00,0x0F,0x12,0x12,0x0E,0x12,0x12,0x0F,0x00, +0x0C,0x12,0x01,0x01,0x01,0x12,0x0C,0x00,0x07,0x09,0x11,0x11,0x11,0x09,0x07,0x00, +0x1F,0x12,0x02,0x0E,0x02,0x12,0x1F,0x00,0x1F,0x12,0x02,0x0E,0x02,0x02,0x07,0x00, +0x01,0x07,0x1F,0x7F,0x1F,0x07,0x01,0x00,0x40,0x70,0x7C,0x7F,0x7C,0x70,0x40,0x00, +0x18,0x3C,0x7E,0x18,0x18,0x7E,0x3C,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00, +0xFE,0xDB,0xDB,0xDE,0xD8,0xD8,0xD8,0x00,0x7C,0xC6,0x1C,0x36,0x36,0x1C,0x33,0x1E, +0x00,0x00,0x00,0x00,0x7E,0x7E,0x7E,0x00,0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0xFF, +0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00, +0x00,0x18,0x30,0x7F,0x30,0x18,0x00,0x00,0x00,0x0C,0x06,0x7F,0x06,0x0C,0x00,0x00, +0x00,0x00,0x03,0x03,0x03,0x7F,0x00,0x00,0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00, +0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0x7E,0x3C,0x18,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00, +0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x7F,0x22,0x7F,0x22,0x22,0x00, +0x04,0x0E,0x01,0x0E,0x10,0x0F,0x04,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00, +0x0E,0x11,0x0A,0x2E,0x11,0x21,0x5E,0x00,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00, +0x10,0x08,0x04,0x04,0x04,0x08,0x10,0x00,0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00, +0x00,0x42,0x24,0xFF,0x24,0x42,0x00,0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00, +0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x1F,0x00, +0x1E,0x21,0x20,0x18,0x06,0x01,0x3F,0x00,0x1E,0x21,0x20,0x18,0x20,0x21,0x1E,0x00, +0x38,0x24,0x22,0x21,0x7F,0x20,0x70,0x00,0x3F,0x01,0x1F,0x20,0x20,0x21,0x1E,0x00, +0x0C,0x02,0x01,0x1F,0x21,0x21,0x1E,0x00,0x3F,0x21,0x20,0x10,0x08,0x08,0x08,0x00, +0x1E,0x21,0x21,0x1E,0x21,0x21,0x1E,0x00,0x1E,0x21,0x21,0x3E,0x20,0x10,0x0E,0x00, +0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x02, +0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00, +0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,0x1E,0x21,0x20,0x10,0x08,0x00,0x08,0x00, +0x3E,0x41,0x41,0x41,0x39,0x01,0x1E,0x00,0x04,0x0A,0x11,0x11,0x1F,0x11,0x11,0x00, +0x1F,0x22,0x22,0x1E,0x22,0x22,0x1F,0x00,0x1C,0x22,0x01,0x01,0x01,0x22,0x1C,0x00, +0x1F,0x22,0x42,0x42,0x42,0x22,0x1F,0x00,0x7F,0x01,0x01,0x0F,0x01,0x01,0x7F,0x00, +0x7F,0x01,0x01,0x0F,0x01,0x01,0x01,0x00,0x3C,0x42,0x01,0x01,0x61,0x42,0x3C,0x00, +0x21,0x21,0x21,0x3F,0x21,0x21,0x21,0x00,0x0E,0x04,0x04,0x04,0x04,0x04,0x0E,0x00, +0x70,0x20,0x20,0x20,0x21,0x21,0x1E,0x00,0x42,0x42,0x22,0x1E,0x22,0x42,0x42,0x00, +0x02,0x02,0x02,0x02,0x02,0x02,0x7E,0x00,0x41,0x63,0x55,0x49,0x41,0x41,0x41,0x00, +0x41,0x43,0x45,0x49,0x51,0x61,0x41,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00, +0x3E,0x42,0x42,0x3E,0x02,0x02,0x02,0x00,0x1E,0x21,0x21,0x21,0x21,0x1E,0x30,0x00, +0x1F,0x21,0x21,0x1F,0x11,0x21,0x21,0x00,0x1E,0x21,0x01,0x1E,0x20,0x21,0x1E,0x00, +0x7F,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x21,0x21,0x21,0x21,0x21,0x21,0x1E,0x00, +0x21,0x21,0x21,0x21,0x21,0x12,0x0C,0x00,0x41,0x41,0x41,0x49,0x55,0x63,0x41,0x00, +0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x11,0x11,0x11,0x0E,0x04,0x04,0x04,0x00, +0x7F,0x20,0x10,0x08,0x04,0x02,0x7F,0x00,0x1E,0x02,0x02,0x02,0x02,0x02,0x1E,0x00, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x1E,0x00, +0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, +0x08,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x20,0x3E,0x21,0x6E,0x00, +0x02,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00,0x00,0x1E,0x21,0x01,0x21,0x1E,0x00, +0x20,0x20,0x20,0x3E,0x21,0x21,0x1E,0x00,0x00,0x00,0x1E,0x21,0x1F,0x01,0x1E,0x00, +0x1C,0x22,0x02,0x0F,0x02,0x02,0x02,0x00,0x00,0x00,0x1E,0x21,0x21,0x3E,0x20,0x1F, +0x02,0x02,0x02,0x3E,0x42,0x42,0x42,0x00,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x00, +0x20,0x00,0x20,0x20,0x20,0x21,0x21,0x1E,0x01,0x01,0x21,0x11,0x0F,0x11,0x21,0x00, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x22,0x55,0x49,0x41,0x41,0x00, +0x00,0x00,0x1F,0x21,0x21,0x21,0x21,0x00,0x00,0x00,0x1E,0x21,0x21,0x21,0x1E,0x00, +0x00,0x00,0x1F,0x21,0x21,0x1F,0x01,0x01,0x00,0x00,0x3E,0x21,0x21,0x3E,0x20,0x20, +0x00,0x00,0x1D,0x23,0x01,0x01,0x01,0x00,0x00,0x00,0x3E,0x01,0x1E,0x20,0x1F,0x00, +0x08,0x08,0x1C,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x21,0x21,0x21,0x21,0x1E,0x00, +0x00,0x00,0x21,0x21,0x21,0x12,0x0C,0x00,0x00,0x00,0x41,0x41,0x49,0x55,0x22,0x00, +0x00,0x00,0x22,0x14,0x08,0x14,0x22,0x00,0x00,0x00,0x21,0x21,0x21,0x3E,0x20,0x1F, +0x00,0x00,0x3F,0x10,0x08,0x04,0x3F,0x00,0x30,0x08,0x08,0x06,0x08,0x08,0x30,0x00, +0x08,0x08,0x08,0x00,0x08,0x08,0x08,0x00,0x03,0x04,0x04,0x18,0x04,0x04,0x03,0x00, +0x6E,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x22,0x41,0x41,0x7F,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static int lcmx; // now character position +static int lcmy; // now dot position + +// LCM register number +#define LCM_REG_MODE_CONTROL 0 // mode control +#define LCM_CMD_DISPLAY_BIT 0x20 +#define LCM_CMD_MASTER_BIT 0x10 +#define LCM_CMD_BLINK_BIT 0x08 +#define LCM_CMD_CURSOR_BIT 0x04 +#define LCM_CMD_MODE_BIT 0x02 +#define LCM_CMD_CG_BIT 0x01 // external CG, 0 for built-in CG +#define LCM_CMD_GRAPHIC_MODE 0x32 // setting the graphic mode +#define LCM_CMD_TEXT_MODE 0x30 // setting the charactic mode +#define LCM_CMD_DISPLAY_ON 0x32 +#define LCM_CMD_DISPLAY_OFF 0x12 +#define LCM_CMD_CURSOR_ON 0x34 +#define LCM_CMD_CURSOR_OFF 0x30 +#define LCM_CMD_CHAR_BLINK 0x38 +#define LCM_CMD_CURSOR_BLINK 0x3c + +#define LCM_REG_SET_CH_PITCH 1 // setting the character pitch +#define LCM_H_PITCH_6 0x05 +#define LCM_H_PITCH_7 0x06 +#define LCM_H_PITCH_8 0x07 + +#define LCM_REG_SET_NO_CH 2 // setting the number of characters +#define LCM_REG_SET_TIME_DIV 3 // setting the time division number +#define LCM_REG_SET_CUR_POS 4 // setting the cursor position +#define LCM_REG_SET_DIS_LADDR 8 // setting the display start lower address +#define LCM_REG_SET_DIS_UADDR 9 // setting the display start upper address +#define LCM_REG_SET_CUR_LADDR 10 // setting the cursor (lower) address +#define LCM_REG_SET_CUR_UADDR 11 // setting the cursor (upper) address +#define LCM_REG_W_DIS_DATA 12 // writing display data +#define LCM_REG_R_DIS_DATA 13 // reading display data + +#define LCM_REG_BIT_CLEAR 14 // bit clear +#define LCM_BIT_CLEAR_MASK 0x07 + +#define LCM_REG_BIT_SET 15 // bit set +#define LCM_BIT_SET 0x07 + +#define LCM_BUSY_FLAG 0x80 // when you read this bit, + // you must set RS & R/W are both high + +// following LCM control +#define LCM_DATA 0 +#define LCM_CMD (1<<8) +#define LCM_READ (1<<9) +#define LCM_WRITE 0 +#define LCM_EBIT_ON (1<<10) +#define LCM_EBIT_OFF 0 +#define LCM_BACK_LIGHT_ON 0 +#define LCM_BACK_LIGHT_OFF (1<<11) +#define LCM_DISPLAY_OFF 0 +#define LCM_DISPLAY_ON (1<<13) +#define LCM_CS_OFF (1<<12) // chip enable "active" L +#define LCM_CS_ON 0 // chip enable "active" L +#define LCM_WRITE_ENABLE 0 +#define LCM_READ_ENABLE (1<<14) + +#define LCM_MAX_X_DOTS 160 // max x dots (colum) +#define LCM_MAX_Y_DOTS 80 // max y dots (row) +#define LCM_X_DOTS 8 // x dots for each character +#define LCM_Y_DOTS 8 // y dots for each character +#define LCM_X_DOTS_MASK (LCM_X_DOTS-1) +#define LCM_Y_DOTS_MASK (LCM_Y_DOTS-1) +#define LCM_X_DOTS_SHIFT 3 +#define LCM_Y_DOTS_SHIFT 3 +#define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS) // max x char. +#define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS) // max y char. + +static unsigned char lcm_pix_buffer[LCM_MAX_X][LCM_MAX_Y_DOTS]; +static u16 lcm_ctrl_data=LCM_DISPLAY_ON|LCM_BACK_LIGHT_ON; +static int lcm_auto_scroll_flag=1; +static int lcm_reverse_flag=0; +static unsigned short lcm_start_ram_address=0; // embedded on LCM module RAM + +typedef struct lcm_xy { + int x; // 0 - LCM_MAX_X + int y; // 0 - LCM_MAX_Y +} lcm_xy_t; + +#define LCM_NOT_LOCK_INT +#if 0 +#define LCM_delay() udelay(1) +#else +#define LCM_delay() +#endif + +static void LCM_write_register(u16 regno, u16 data) +{ +#ifndef LCM_NOT_LOCK_INT + unsigned long flags; + + save_flags(flags); + cli(); +#endif + spin_lock(&lcm_lock); + + // first write the register number + //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|LCM_CS_ON, LCM_WRITE_ADDR); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR); + LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR); + LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR); + //LCM_delay(); + //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|LCM_CS_OFF, LCM_WRITE_ADDR); + + // second write the data for this register + //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|LCM_CS_ON, LCM_WRITE_ADDR); + //LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR); + LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR); + LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR); + //LCM_delay(); + outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|LCM_CS_OFF, LCM_WRITE_ADDR); + + spin_unlock(&lcm_lock); +#ifndef LCM_NOT_LOCK_INT + restore_flags(flags); +#endif +} + +static void lcm_up_one_line(void) +{ + int x, y; + + // first up one line for lcm buffer + spin_lock(&lcm_lock); + for ( y=1; y> 8) & 0xff); + + // second redisplay up one line on LCM + LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_OFF); + for ( y=0; y= LCM_MAX_Y_DOTS ) { + if ( lcm_auto_scroll_flag ) { + lcmy = (LCM_MAX_Y - 1) * LCM_Y_DOTS; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + spin_unlock(&lcm_lock); + return; + } + + index = ch * LCM_X_DOTS; + for ( i=0, k=lcmy; i> 8) & 0xff); + LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[lcmx][k]); + } + + spin_lock(&lcm_lock); + lcmx++; + if ( lcmx >= LCM_MAX_X ) { + lcmx = 0; + lcmy += LCM_Y_DOTS; + if ( lcmy >= LCM_MAX_Y_DOTS ) { + if ( lcm_auto_scroll_flag ) { + lcmy = (LCM_MAX_Y - 1) * LCM_Y_DOTS; + spin_unlock(&lcm_lock); + lcm_up_one_line(); + return; + } else { + lcmy = 0; + } + } + } + spin_unlock(&lcm_lock); +} + +static void LCM_clear_line(void) +{ + int x, i; + + for ( x=0; x> 8) & 0xff); + for ( i=0; i> 8) & 0xff); + + for ( y=0; y> 8) & 0xff); + + spin_lock(&lcm_lock); + lcmx = lcmy = 0; + spin_unlock(&lcm_lock); +} + +/* + * I don't know why cannot malloc memory from kernel. + * 03-10-2004 Victor Yu. + */ +#define USE_WRITE_BUFFER +#ifdef USE_WRITE_BUFFER +static char write_buffer[LCM_MAX_X * LCM_MAX_Y]; +#endif +static ssize_t lcm_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) +{ +#ifndef USE_WRITE_BUFFER + char *ptr; +#endif + int i; + + if ( count == 0 ) + return 0; +#ifdef USE_WRITE_BUFFER + if ( count > (LCM_MAX_X * LCM_MAX_Y) ) + count = LCM_MAX_X * LCM_MAX_Y; + if ( copy_from_user(write_buffer, buf, count) ) { + return -EFAULT; + } + for ( i=0; i= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + x = pos.x >> LCM_X_DOTS_SHIFT; + v = lcm_pix_buffer[x][pos.y]; + mask = 1 << (pos.x & LCM_X_DOTS_MASK); + if ( cmd == IOCTL_LCM_PIX_ON ) + v |= mask; + else + v &= ~mask; + lcm_pix_buffer[x][pos.y] = v; + spin_unlock(&lcm_lock); + i = (pos.y * LCM_MAX_X) + x + lcm_start_ram_address; + LCM_write_register(LCM_REG_SET_CUR_LADDR, i & 0xff); + LCM_write_register(LCM_REG_SET_CUR_UADDR, (i >> 8) & 0xff); + LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][pos.y]); + break; + } + case IOCTL_LCM_GOTO_XY : + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y ) + return -EINVAL; + spin_lock(&lcm_lock); + lcmx = pos.x; + lcmy = pos.y * LCM_Y_DOTS; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_CLS : + LCM_cls(); + break; + case IOCTL_LCM_CLEAN_LINE : + LCM_clear_line(); + break; + case IOCTL_LCM_GET_XY : + spin_lock(&lcm_lock); + pos.x = lcmx; + pos.y = lcmy / LCM_Y_DOTS; + spin_unlock(&lcm_lock); + if ( copy_to_user((void *)arg, &pos,sizeof(pos)) ) + return -EFAULT; + break; + case IOCTL_LCM_BACK_LIGHT_ON : + spin_lock(&lcm_lock); + lcm_ctrl_data &= ~LCM_BACK_LIGHT_OFF; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_BACK_LIGHT_OFF : + spin_lock(&lcm_lock); + lcm_ctrl_data |= LCM_BACK_LIGHT_OFF; + outw(lcm_ctrl_data, LCM_WRITE_ADDR); + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_ON : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_AUTO_SCROLL_OFF : + spin_lock(&lcm_lock); + lcm_auto_scroll_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_ON : + spin_lock(&lcm_lock); + lcm_reverse_flag = 1; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_REVERSE_OFF : + spin_lock(&lcm_lock); + lcm_reverse_flag = 0; + spin_unlock(&lcm_lock); + break; + case IOCTL_LCM_SAVE_BYTE : + if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) ) + return -EFAULT; + break; + case IOCTL_LCM_WRITE_BYTE : + { + int i, x; + if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) ) + return -EFAULT; + if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS ) + return -EINVAL; + spin_lock(&lcm_lock); + x = pos.x >> LCM_X_DOTS_SHIFT; + lcm_pix_buffer[x][pos.y] = user_data; + spin_unlock(&lcm_lock); + i = (pos.y * LCM_MAX_X) + x + lcm_start_ram_address; + LCM_write_register(LCM_REG_SET_CUR_LADDR, i & 0xff); + LCM_write_register(LCM_REG_SET_CUR_UADDR, (i >> 8) & 0xff); + LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][pos.y]); + break; + } + case IOCTL_LCM_DISPLAY_OFF : + LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_OFF); + break; + case IOCTL_LCM_DISPLAY_ON : + LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_ON); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int lcm_open(struct inode *inode, struct file *file) +{ + if ( MINOR(inode->i_rdev) == MOXA_LCM_MINOR ) + return 0; + return -ENODEV; +} + +static int lcm_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations lcm_fops = { + owner:THIS_MODULE, + llseek:NULL, + write:lcm_write, + ioctl:lcm_ioctl, + open:lcm_open, + release:lcm_release, +}; +static struct miscdevice lcm_dev = { + MOXA_LCM_MINOR, + "lcm", + &lcm_fops +}; + +#if 1 // add by Victor Yu. 04-03-2007 +extern int lcm_module_flag; +#endif +static void __exit ivtc_lcm3_exit(void) +{ + misc_deregister(&lcm_dev); + lcm_module_flag = 0; +} + +static int __init ivtc_lcm3_init(void) +{ + printk("Moxa CPU misc: Register LCM module WG16080A misc ver1.0 "); + if ( lcm_module_flag ) { + printk("fail !\nThe other type LCM module device driver has loaded.\n"); + return -ENOMEM; + } + if ( misc_register(&lcm_dev) ) { + printk("fail !\n"); + return -ENOMEM; + } + lcm_module_flag = 1; + printk("OK.\n"); + + // setting the LCM to be graphic mode + LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_GRAPHIC_MODE); + LCM_write_register(LCM_REG_SET_CH_PITCH, 0x77); + LCM_write_register(LCM_REG_SET_NO_CH, LCM_MAX_X-1); + LCM_write_register(LCM_REG_SET_TIME_DIV, LCM_MAX_Y_DOTS-1); + + // setting the start address is from 0 + LCM_write_register(LCM_REG_SET_DIS_LADDR, lcm_start_ram_address & 0xff); + LCM_write_register(LCM_REG_SET_DIS_UADDR, (lcm_start_ram_address >> 8) & 0xff); + LCM_write_register(LCM_REG_SET_CUR_LADDR, lcm_start_ram_address & 0xff); + LCM_write_register(LCM_REG_SET_CUR_UADDR, (lcm_start_ram_address >> 8) & 0xff); + + LCM_cls(); + return 0; +} + +module_init(ivtc_lcm3_init); +module_exit(ivtc_lcm3_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/ledman.c b/drivers/char/ledman.c new file mode 100644 index 00000000..3de22e7d --- /dev/null +++ b/drivers/char/ledman.c @@ -0,0 +1,2189 @@ +/****************************************************************************/ +/* vi:set tabstop=4 cindent shiftwidth=4: + * + * ledman.c -- An LED manager, primarily, but not limited to SnapGear + * devices manages up to 32 seperate LED at once. + * Copyright (C) Lineo, 2000-2001. + * Copyright (C) SnapGear, 2001-2003. + * + * This driver currently supports 4 types of LED modes: + * + * SET - transient LED's that show activity, cleared at next poll + * ON - always ON + * OFF - always OFF + * FLASHING - a blinking LED with the frequency determined by the poll func + * + * We have two sets of LED's to support non-standard LED usage without + * losing previously/during use set of std values. + * + * Hopefully for most cases, adding new HW with new LED patterns will be + * as simple as adding two tables, a small function and an entry in + * led_modes. The tables being the map and the defaults while the + * function is the XXX_set function. + * + * You can, however, add your own functions for XXX_bits, XXX_tick and + * take full control over all aspects of the LED's. + */ +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < 0x020300 +#include +#else +#include +#endif + +#if LINUX_VERSION_CODE < 0x020100 +#define INIT_RET_TYPE int +#define Module_init(a) +#elif LINUX_VERSION_CODE < 0x020300 +#include +#define INIT_RET_TYPE int +#define Module_init(a) module_init(a) +#else +#include +#define INIT_RET_TYPE static int __init +#define Module_init(a) module_init(a) +#endif + +#if LINUX_VERSION_CODE < 0x020100 +#define Get_user(a,b) a = get_user(b) +#else +#include +#define Get_user(a,b) get_user(a,b) +#endif + +#if LINUX_VERSION_CODE < 0x020100 +static struct symbol_table ledman_syms = { +#include + X(ledman_cmd), +#include +}; +#else +EXPORT_SYMBOL(ledman_cmd); +#endif + +/****************************************************************************/ + +static void ledman_poll(unsigned long arg); +static int ledman_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +#if !defined(CONFIG_SH_KEYWEST) && !defined(CONFIG_SH_BIGSUR) +static int ledman_bits(unsigned long cmd, unsigned long bits); +static void ledman_tick(void); +#endif + +/****************************************************************************/ + +static struct timer_list ledman_timerlist; + +/****************************************************************************/ + +struct file_operations ledman_fops = { + .ioctl = ledman_ioctl, +}; + +/****************************************************************************/ +/* + * some types to make adding new LED modes easier + * + * First the elements for def array specifying default LED behaviour + */ + +#define LEDS_SET 0 +#define LEDS_ON 1 +#define LEDS_OFF 2 +#define LEDS_FLASH 3 +#define LEDS_MAX 4 + +typedef unsigned long leddef_t[LEDS_MAX]; + +/* + * A LED map is a mapping from numbers in ledman.h to one or more + * physical LED bits. Currently the typing limits us to 32 LED's + * though this would not be hard to change. + */ + +typedef unsigned long ledmap_t[LEDMAN_MAX]; + +/* + * A LED mode is a definition of how a set of LED's should behave. + * + * name - a symbolic name for the LED mode, used for changing modes + * map - points to a ledmap array, maps ledman.h defines to real LED bits + * def - default behaviour for the LED bits (ie, on, flashing ...) + * bits - perform command on physical bits, you may use the default or + * supply your own for more control. + * tick - time based update of LED status, used to clear SET LED's and + * also for flashing LED's + * set - set the real LED's to match the physical bits + * jiffies - how many clock ticks between runs of the tick routine. + */ + + +typedef struct { + char name[LEDMAN_MAX_NAME]; + u_long *map; + u_long *def; + int (*bits)(unsigned long cmd, unsigned long led); + void (*tick)(void); + void (*set)(unsigned long led); + int jiffies; +} ledmode_t; + +/****************************************************************************/ + +static int current_mode = 0; /* the default LED mode */ +static int initted = 0; + +/* + * We have two sets of LED's for transient operations like DHCP and so on + * index 0 is the standard LED's and index 1 is the ALTBIT LED's + */ + +static unsigned long leds_alt, leds_alt_cnt[32]; +#if !defined(CONFIG_SH_KEYWEST) && !defined(CONFIG_SH_BIGSUR) +static unsigned long leds_set[2]; +#endif +static unsigned long leds_on[2], leds_off[2], leds_flash[2]; + +static pid_t ledman_resetpid = -1; + +/****************************************************************************/ + +/* + * Let the system specific defining begin + */ + +#if defined(CONFIG_M586) +#define CONFIG_X86 1 +#endif + +#if defined(CONFIG_X86) +#if defined(CONFIG_MTD_SNAPGEODE) +#define CONFIG_GEODE 1 +#else +#define CONFIG_AMDSC520 1 +#endif +#if defined(CONFIG_SNAPGEAR) +static ledmap_t nettel_old; +static leddef_t nettel_def_old; +#endif +static ledmap_t nettel_std; +static leddef_t nettel_def; +static void nettel_set(unsigned long bits); +static void ledman_initarch(void); +#endif /* CONFIG_X86 */ + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) +#ifdef ENTERASYS +static ledmap_t enterasys_std; +static leddef_t enterasys_def; +#endif +static ledmap_t nettel_old; +static ledmap_t nettel_new; +static leddef_t nettel_def; +static void nettel_set(unsigned long bits); +#endif + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5272) +static ledmap_t nt5272_std; +static leddef_t nt5272_def; +static void nt5272_set(unsigned long bits); +#endif + +#if defined(CONFIG_SE1100) +static ledmap_t se1100_std; +static leddef_t se1100_def; +static void se1100_set(unsigned long bits); +#endif + +#if defined(CONFIG_GILBARCONAP) && defined(CONFIG_M5272) +static ledmap_t nap5272_std; +static leddef_t nap5272_def; +static void nap5272_set(unsigned long bits); +#endif + +#if defined(CONFIG_AVNET5282) +static ledmap_t ads5282_std; +static leddef_t ads5282_def; +static void ads5282_set(unsigned long bits); +#endif + +#if defined(CONFIG_SH_SECUREEDGE5410) +#include +static ledmap_t se5410_std; +static leddef_t se5410_def; +static void se5410_set(unsigned long bits); +#endif + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5206e) +static ledmap_t nt1500_std; +static leddef_t nt1500_def; +static void nt1500_set(unsigned long bits); +#endif + +#ifdef CONFIG_eLIA +static ledmap_t elia_std; +static leddef_t elia_def; +static void elia_set(unsigned long bits); +#endif + +#if defined(CONFIG_SH_KEYWEST) || defined(CONFIG_SH_BIGSUR) +static ledmap_t keywest_std; +static leddef_t keywest_def; +static void keywest_set(unsigned long bits); +static void ledman_initkeywest(void); +static int keywest_bits(unsigned long cmd, unsigned long bits); +static void keywest_tick(void); +#endif + +#if defined(CONFIG_MACH_MONTEJADE) || defined(CONFIG_MACH_IXDPG425) || \ + defined(CONFIG_MACH_SE5100) +static ledmap_t montejade_std; +static leddef_t montejade_def; +static void ledman_initarch(void); +static void montejade_set(unsigned long bits); +#endif + +#if defined(CONFIG_ARCH_SE4000) || defined(CONFIG_MACH_ESS710) || \ + defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \ + defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SG640) || \ + defined(CONFIG_MACH_SG720) || defined(CONFIG_MACH_SG590) || \ + defined(CONFIG_MACH_SG8100) +static ledmap_t snapgear425_std; +static leddef_t snapgear425_def; +static void ledman_initarch(void); +static void snapgear425_set(unsigned long bits); +#endif + +#ifdef CONFIG_MACH_IVPN +static ledmap_t ivpn_std; +static leddef_t ivpn_def; +static void ledman_initarch(void); +static void ivpn_set(unsigned long bits); +#endif + +#ifdef CONFIG_ARCH_KS8695 +static ledmap_t lite3_std; +static leddef_t lite3_def; +static void ledman_initarch(void); +static void lite3_set(unsigned long bits); +#endif + +#ifdef CONFIG_ARCH_EP9312 +static ledmap_t ipd_std; +static leddef_t ipd_def; +static void ledman_initarch(void); +static void ipd_set(unsigned long bits); +#endif + +/****************************************************************************/ +/****************************************************************************/ + +#undef LT +#define LT (((HZ) + 99) / 100) + +/****************************************************************************/ + +ledmode_t led_mode[] = { + +#ifdef ENTERASYS /* first in the list is the default */ + { "enterasys", enterasys_std, enterasys_def, ledman_bits, ledman_tick, nettel_set, LT }, +#endif + +#if defined(CONFIG_X86) + { "std", nettel_std, nettel_def, ledman_bits, ledman_tick, nettel_set, LT }, +#if defined(CONFIG_SNAPGEAR) + { "old", nettel_old, nettel_def_old, ledman_bits, ledman_tick, nettel_set, LT }, +#endif +#endif + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) + /* + * by default the first entry is used. You can select the old-style + * LED patterns for acient boards with the command line parameter: + * + * ledman=old + */ + { "new", nettel_new, nettel_def, ledman_bits, ledman_tick, nettel_set, LT }, + { "old", nettel_old, nettel_def, ledman_bits, ledman_tick, nettel_set, LT }, +#endif + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5272) + { "std", nt5272_std, nt5272_def, ledman_bits, ledman_tick, nt5272_set, LT }, +#endif + +#if defined(CONFIG_NETtel) && defined(CONFIG_M5206e) + { "std", nt1500_std, nt1500_def, ledman_bits, ledman_tick, nt1500_set, LT }, +#endif + +#if defined(CONFIG_SE1100) + { "std", se1100_std, se1100_def, ledman_bits, ledman_tick, se1100_set, LT }, +#endif + +#if defined(CONFIG_GILBARCONAP) && defined(CONFIG_M5272) + { "std", nap5272_std, nap5272_def, ledman_bits, ledman_tick, nap5272_set, LT }, +#endif + +#if defined(CONFIG_SH_SECUREEDGE5410) + { "std", se5410_std, se5410_def, ledman_bits, ledman_tick, se5410_set, LT }, +#endif + +#ifdef CONFIG_eLIA + { "std", elia_std, elia_def, ledman_bits, ledman_tick, elia_set, LT }, +#endif + +#if defined(CONFIG_SH_KEYWEST) || defined(CONFIG_SH_BIGSUR) + { "std",keywest_std,keywest_def,keywest_bits,keywest_tick,keywest_set,HZ/10}, +#endif + +#if defined(CONFIG_MACH_MONTEJADE) || defined(CONFIG_MACH_IXDPG425) || \ + defined(CONFIG_MACH_SE5100) + { "std",montejade_std,montejade_def,ledman_bits,ledman_tick,montejade_set,LT}, +#endif + +#if defined(CONFIG_ARCH_SE4000) || defined(CONFIG_MACH_ESS710) || \ + defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \ + defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SG640) || \ + defined(CONFIG_MACH_SG720) || defined(CONFIG_MACH_SG590) || \ + defined(CONFIG_MACH_SG8100) + { "std",snapgear425_std,snapgear425_def,ledman_bits,ledman_tick,snapgear425_set,LT}, +#endif + +#ifdef CONFIG_MACH_IVPN + { "std",ivpn_std,ivpn_def,ledman_bits,ledman_tick,ivpn_set,LT}, +#endif + +#if defined(CONFIG_ARCH_KS8695) + { "std",lite3_std,lite3_def,ledman_bits,ledman_tick,lite3_set,LT}, +#endif + +#if defined(CONFIG_ARCH_EP9312) + { "std", ipd_std, ipd_def, ledman_bits, ledman_tick, ipd_set, LT}, +#endif + +#if defined(CONFIG_AVNET5282) + { "std", ads5282_std, ads5282_def, ledman_bits, ledman_tick, ads5282_set, LT }, +#endif + + { "", NULL, NULL, NULL } +}; + +/****************************************************************************/ +/* + * boot arg processing ledman=mode + */ + +#if LINUX_VERSION_CODE >= 0x020100 +__setup("ledman=", ledman_setup); +#endif + +int +ledman_setup(char *arg) +{ + ledman_cmd(LEDMAN_CMD_MODE, (unsigned long) arg); + return(0); +} + +/****************************************************************************/ +/****************************************************************************/ + +INIT_RET_TYPE ledman_init(void) +{ + int expires; + printk(KERN_INFO "ledman: Copyright (C) SnapGear, 2000-2003.\n"); + + if (register_chrdev(LEDMAN_MAJOR, "nled", &ledman_fops) < 0) { + printk("%s(%d): ledman_init() can't get Major %d\n", + __FILE__, __LINE__, LEDMAN_MAJOR); + return(-EBUSY); + } + +#if defined(CONFIG_SH_KEYWEST) || defined(CONFIG_SH_BIGSUR) + ledman_initkeywest(); +#endif + +#if defined(CONFIG_X86) || defined(CONFIG_ARM) + ledman_initarch(); +#endif + +/* + * set the LEDs up correctly at boot + */ + ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_ALL); +/* + * start the timer + */ + init_timer(&ledman_timerlist); + if (led_mode[current_mode].tick) + expires = jiffies + led_mode[current_mode].jiffies; + else + expires = jiffies + HZ; + ledman_timerlist.function = ledman_poll; + ledman_timerlist.data = 0; + mod_timer(&ledman_timerlist, expires); + +#if LINUX_VERSION_CODE < 0x020100 + register_symtab(&ledman_syms); +#endif + + initted = 1; + return 0; +} + +Module_init(ledman_init); + +/****************************************************************************/ + +void +ledman_killtimer(void) +{ +/* + * stop the timer + */ + del_timer(&ledman_timerlist); + +/* + * set the LEDs up correctly at boot + */ + ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_ALL); +} + +/****************************************************************************/ + +void +ledman_starttimer(void) +{ +/* + * start the timer + */ + mod_timer(&ledman_timerlist, jiffies + 1); + +/* + * set the LEDs up correctly at boot + */ + ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_ALL); +} + +/****************************************************************************/ + +static void +ledman_poll(unsigned long arg) +{ + int expires; + if (led_mode[current_mode].tick) { + (*led_mode[current_mode].tick)(); + expires = jiffies + led_mode[current_mode].jiffies; + } else + expires = jiffies + HZ; + mod_timer(&ledman_timerlist, expires); +} + +/****************************************************************************/ + +static int +ledman_ioctl( + struct inode * inode, + struct file * file, + unsigned int cmd, + unsigned long arg) +{ + char mode[LEDMAN_MAX_NAME]; + int i; + + if (cmd == LEDMAN_CMD_SIGNAL) { + ledman_resetpid = current->pid; + return(0); + } + + if (cmd == LEDMAN_CMD_MODE) { + for (i = 0; i < sizeof(mode) - 1; i++) { + Get_user(mode[i], (char __user *) (arg + i)); + if (!mode[i]) + break; + } + mode[i] = '\0'; + arg = (unsigned long) &mode[0]; + } + return(ledman_cmd(cmd, arg)); +} + +/****************************************************************************/ +/* + * cmd - from ledman.h + * led - led code from ledman.h + * + * check parameters and then call + */ + +int +ledman_cmd(int cmd, unsigned long led) +{ + ledmode_t *lmp; + int i; + + switch (cmd & ~LEDMAN_CMD_ALTBIT) { + case LEDMAN_CMD_SET: + case LEDMAN_CMD_ON: + case LEDMAN_CMD_OFF: + case LEDMAN_CMD_FLASH: + case LEDMAN_CMD_RESET: + case LEDMAN_CMD_ALT_ON: + case LEDMAN_CMD_ALT_OFF: + break; + case LEDMAN_CMD_STARTTIMER: + ledman_starttimer(); + return(0); + case LEDMAN_CMD_KILLTIMER: + ledman_killtimer(); + return(0); + case LEDMAN_CMD_MODE: + for (i = 0; led_mode[i].name[0]; i++) + if (strcmp((char *) led, led_mode[i].name) == 0) { + current_mode = i; + if (initted) + ledman_cmd(LEDMAN_CMD_RESET, LEDMAN_ALL); + return(0); + } + return(-EINVAL); + default: + return(-EINVAL); + } + + if (led < 0 || led >= LEDMAN_MAX) + return(-EINVAL); + + lmp = &led_mode[current_mode]; + (*lmp->bits)(cmd, lmp->map[led]); + return(0); +} + +/****************************************************************************/ +/* + * Signal the reset pid, if we have one + */ + +void +ledman_signalreset(void) +{ + static unsigned long firstjiffies = 0; + if (ledman_resetpid == -1) + return; + if (jiffies > (firstjiffies + (HZ / 4))) { + firstjiffies = jiffies; + printk("LED: reset switch interrupt! (sending signal to pid=%d)\n", + ledman_resetpid); + kill_proc(ledman_resetpid, SIGUSR2, 1); + } +} + +/****************************************************************************/ +#if !defined(CONFIG_SH_KEYWEST) && !defined(CONFIG_SH_BIGSUR) +/****************************************************************************/ + +static int +ledman_bits(unsigned long cmd, unsigned long bits) +{ + ledmode_t *lmp = &led_mode[current_mode]; + int alt, i; + unsigned long new_alt; + + alt = (cmd & LEDMAN_CMD_ALTBIT) ? 1 : 0; + + switch (cmd & ~LEDMAN_CMD_ALTBIT) { + case LEDMAN_CMD_SET: + leds_set[alt] |= bits; + break; + case LEDMAN_CMD_ON: + leds_on[alt] |= bits; + leds_off[alt] &= ~bits; + leds_flash[alt] &= ~bits; + (*lmp->tick)(); + break; + case LEDMAN_CMD_OFF: + leds_on[alt] &= ~bits; + leds_off[alt] |= bits; + leds_flash[alt] &= ~bits; + (*lmp->tick)(); + break; + case LEDMAN_CMD_FLASH: + leds_on[alt] &= ~bits; + leds_off[alt] &= ~bits; + leds_flash[alt] |= bits; + break; + case LEDMAN_CMD_RESET: + leds_set[alt] = (leds_set[alt] &~bits) | (bits&lmp->def[LEDS_SET]); + leds_on[alt] = (leds_on[alt] &~bits) | (bits&lmp->def[LEDS_ON]); + leds_off[alt] = (leds_off[alt] &~bits) | (bits&lmp->def[LEDS_OFF]); + leds_flash[alt] = (leds_flash[alt]&~bits) | (bits&lmp->def[LEDS_FLASH]); + break; + case LEDMAN_CMD_ALT_ON: + new_alt = (bits & ~leds_alt); + leds_alt |= bits; + /* + * put any newly alt'd bits into a default state + */ + (*lmp->bits)(LEDMAN_CMD_RESET | LEDMAN_CMD_ALTBIT, new_alt); + for (i = 0; i < 32; i++) + if (bits & (1 << i)) + leds_alt_cnt[i]++; + break; + case LEDMAN_CMD_ALT_OFF: + for (i = 0; i < 32; i++) + if ((bits & (1 << i)) && leds_alt_cnt[i]) { + leds_alt_cnt[i]--; + if (leds_alt_cnt[i] == 0) + leds_alt &= ~(1 << i); + } + break; + default: + return(-EINVAL); + } + return(0); +} + +/****************************************************************************/ + +static void +ledman_tick(void) +{ + ledmode_t *lmp = &led_mode[current_mode]; + int new_value; + static int flash_on = 0; +/* + * work out which LED's should be on + */ + new_value = 0; + new_value |= (((leds_set[0] | leds_on[0]) & ~leds_off[0]) & ~leds_alt); + new_value |= (((leds_set[1] | leds_on[1]) & ~leds_off[1]) & leds_alt); +/* + * flashing LED's run on their own devices, ie, according to the + * value fo flash_on + */ + if ((flash_on++ % 60) >= 30) + new_value |= ((leds_flash[0]&~leds_alt) | (leds_flash[1]&leds_alt)); + else + new_value &= ~((leds_flash[0]&~leds_alt) | (leds_flash[1]&leds_alt)); +/* + * set the HW + */ + (*lmp->set)(new_value); + leds_set[0] = leds_set[1] = 0; +} + +/****************************************************************************/ +#endif /* !defined(CONFIG_SH_KEYWEST) && !defined(CONFIG_SH_BIGSUR) */ +/****************************************************************************/ +#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) +/****************************************************************************/ +/* + * Here it the definition of the LED's on the NETtel circuit board + * as per the labels next to them. The two parallel port LED's steal + * some high bits so we can map it more easily onto the HW + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 D11 D12 + * HEX - 100 200 004 008 010 020 040 080 002 001 + * + */ + +#include +#include +#include + +static ledmap_t nettel_old = { + 0x3ff, 0x200, 0x100, 0x008, 0x004, 0x020, 0x010, 0x080, 0x080, 0x080, + 0x080, 0x040, 0x040, 0x002, 0x002, 0x024, 0x018, 0x001, 0x0ff, 0x0ff, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x100, 0x200, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +#if defined(CONFIG_SNAPGEAR) + +/* + * all snapgear 5307 based boards have a SW link status on the front + */ + +static ledmap_t nettel_new = { + 0x3ff, 0x200, 0x100, 0x040, 0x040, 0x002, 0x002, 0x008, 0x008, 0x020, + 0x020, 0x000, 0x000, 0x000, 0x000, 0x024, 0x018, 0x001, 0x0ff, 0x080, + 0x000, 0x000, 0x080, 0x004, 0x010, 0x000, 0x000, 0x100, 0x200, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +#else + +static ledmap_t nettel_new = { + 0x3ff, 0x200, 0x100, 0x040, 0x040, 0x002, 0x002, 0x008, 0x004, 0x020, + 0x010, 0x000, 0x000, 0x000, 0x000, 0x024, 0x018, 0x001, 0x0ff, 0x080, + 0x000, 0x000, 0x080, 0x000, 0x000, 0x000, 0x000, 0x100, 0x200, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +#endif + +static leddef_t nettel_def = { + 0x000, 0x200, 0x000, 0x100, +}; + +#ifdef ENTERASYS +static ledmap_t enterasys_std = { + 0x3ff, 0x200, 0x100, 0x040, 0x040, 0x002, 0x002, 0x008, 0x004, 0x020, + 0x010, 0x000, 0x000, 0x000, 0x000, 0x024, 0x018, 0x001, 0x00c, 0x030, + 0x000, 0x000, 0x080, 0x000, 0x000, 0x000, 0x000, 0x100, 0x200, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t enterasys_def = { + 0x000, 0x200, 0x000, 0x100, +}; +#endif + +static void +nettel_set(unsigned long bits) +{ + unsigned long flags; + + save_flags(flags); cli(); + * (volatile char *) NETtel_LEDADDR = (~bits & 0xff); + mcf_setppleds(0x60, ~(bits >> 3) & 0x60); + restore_flags(flags); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_NETtel) && defined(CONFIG_M5307) */ +/****************************************************************************/ +#if defined(CONFIG_NETtel) && defined(CONFIG_M5272) +/****************************************************************************/ + +/* + * For the SecureEdge Firewall (5272), 5 operational LED's. + * + * LED - POWER HEARTBEAT TX RX VPN + * HEX - 001 002 004 008 010 + */ + +#include +#include +#include + +static ledmap_t nt5272_std = { + 0x01f, 0x001, 0x002, 0x008, 0x004, 0x008, 0x004, 0x000, 0x000, 0x008, + 0x004, 0x000, 0x000, 0x000, 0x000, 0x014, 0x008, 0x010, 0x01c, 0x010, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nt5272_def = { + 0x000, 0x001, 0x000, 0x002, +}; + +static void nt5272_set(unsigned long bits) +{ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = (~bits & 0x1f); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_NETtel) && defined(CONFIG_M5272) */ +/****************************************************************************/ +#if defined(CONFIG_SE1100) +/****************************************************************************/ + +/* + * For the SecureEdge SE1100 (5272), 3 operational LED's. + * + * LED - RUNNING INTERNAL1 INTERNAL2 + * HEX - 001 200 002 + */ + +#include +#include +#include + +static ledmap_t se1100_std = { + 0x203, 0x000, 0x001, 0x200, 0x200, 0x200, 0x200, 0x000, 0x000, 0x000, + 0x000, 0x002, 0x002, 0x002, 0x002, 0x200, 0x002, 0x000, 0x202, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t se1100_def = { + 0x000, 0x000, 0x000, 0x001 +}; + +static void se1100_set(unsigned long bits) +{ + mcf_setpa(0x203, bits & 0x203); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_SE1100) */ +/****************************************************************************/ +#if defined(CONFIG_GILBARCONAP) && defined(CONFIG_M5272) +/****************************************************************************/ + +/* + * For the Gilbarco/NAP (5272), 2 operational LED's. + * + * LED - RUNNING DIAG + * HEX - 001 002 + */ + +#include +#include +#include + +static ledmap_t nap5272_std = { + 0x003, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x002, 0x001, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nap5272_def = { + 0x000, 0x001, 0x000, 0x002, +}; + +static void nap5272_set(unsigned long bits) +{ + mcf_setpa(0x3, ~bits & 0x3); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_SE1100) */ +/****************************************************************************/ +#if defined(CONFIG_AVNET5282) +/****************************************************************************/ + +#include +#include + +#define GPTASYSCR1 (*(volatile unsigned char *)0x401a0006) +#define GPTBSYSCR1 (*(volatile unsigned char *)0x401b0006) +#define GPTADR (*(volatile unsigned char *)0x401a001d) +#define GPTBDR (*(volatile unsigned char *)0x401b001d) +#define GPTADDR (*(volatile unsigned char *)0x401a001e) +#define GPTBDDR (*(volatile unsigned char *)0x401b001e) +#define PORT_TC (*(volatile unsigned char *)0x4010000f) +#define PORT_TD (*(volatile unsigned char *)0x40100010) +#define DDR_TC (*(volatile unsigned char *)0x40100023) +#define DDR_TD (*(volatile unsigned char *)0x40100024) +#define DR_TC (*(volatile unsigned char *)0x40100037) +#define DR_TD (*(volatile unsigned char *)0x40100038) + + +static ledmap_t ads5282_std = { + 0x003, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x002, 0x001, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t ads5282_def = { + 0x000, 0x001, 0x000, 0x002, +}; + +static void ads5282_set(unsigned long bits) +{ + static int first_call = 1; + + if (first_call) { + GPTASYSCR1 = 0x00; + GPTBSYSCR1 = 0x00; + GPTADDR = 0x00; + GPTBDDR = 0x0f; + DDR_TC = 0x05; + DDR_TD = 0x05; + first_call = 0; + } + + if (bits & 0x01) PORT_TC &= ~0x01; else PORT_TC |= 0x01; + if (bits & 0x02) PORT_TC &= ~0x04; else PORT_TC |= 0x04; + if (bits & 0x04) PORT_TD &= ~0x01; else PORT_TD |= 0x01; + if (bits & 0x08) PORT_TD &= ~0x04; else PORT_TD |= 0x04; + if (bits & 0x10) GPTBDR &= ~0x01; else GPTBDR |= 0x01; + if (bits & 0x20) GPTBDR &= ~0x02; else GPTBDR |= 0x02; + if (bits & 0x40) GPTBDR &= ~0x04; else GPTBDR |= 0x04; + if (bits & 0x80) GPTBDR &= ~0x08; else GPTBDR |= 0x08; +} + +/****************************************************************************/ +#endif /* defined(CONFIG_AVNET5282) */ +/****************************************************************************/ +#if defined(CONFIG_SH_SECUREEDGE5410) +/****************************************************************************/ + +/* + * For the SecureEdge5410 7 (or 8 for eth2/DMZ port) operational LED's. + * + * LED - POWR HBEAT LAN1 LAN2 | LAN3 | COM ONLINE VPN + * POS - D2 D3 D4 D5 | ?? | D6 D7 D8 DTR + * HEX - 01 02 04 08 |0x2000| 10 20 40 80 + */ + +#include +#if defined(CONFIG_LEDMAP_TAMS_SOHO) +/* + * LED - POWR HBEAT LAN1 LAN2 COM ONLINE VPN + * POS - D2 D3 D4 D5 ?? D6 D7 DTR + * HEX - 01 02 04 08 0x2000 10 20 80 + */ +static ledmap_t se5410_std = { + 0x203f,0x0001,0x0002,0x2000,0x2000,0x2000,0x2000,0x0004,0x0004,0x0008, + 0x0008,0x0000,0x0000,0x0000,0x0000,0x2024,0x0018,0x0020,0x203c,0x0000, + 0x0000,0x0000,0x0010,0x0000,0x0000,0x0000,0x0000,0x0001,0x0002,0x0000, + 0x0000,0x0000,0x0000,0x0000 +}; +#else +static ledmap_t se5410_std = { + 0x207f,0x0001,0x0002,0x0010,0x0010,0x0010,0x0010,0x0004,0x0004,0x0008, + 0x0008,0x0000,0x0000,0x0000,0x0000,0x2054,0x0028,0x0040,0x207c,0x0000, + 0x0000,0x0000,0x0020,0x0000,0x0000,0x0000,0x0000,0x0001,0x0002,0x2000, + 0x2000,0x0000,0x0000,0x0000 +}; +#endif + +static leddef_t se5410_def = { + 0x0000, 0x0001, 0x0000, 0x0002, +}; + +static void se5410_set(unsigned long bits) +{ + unsigned long flags; + + save_and_cli(flags); + SECUREEDGE_WRITE_IOPORT(~bits, 0x207f); + restore_flags(flags); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_GILBARCONAP) && defined(CONFIG_M5272) */ +/****************************************************************************/ +#if defined(CONFIG_NETtel) && defined(CONFIG_M5206e) +/****************************************************************************/ +/* + * For the WebWhale/NETtel1500, 3 LED's (was 2) + * + * LED - HEARTBEAT DCD DATA + * HEX - 001 002 004 + */ + +#include +#include +#include + +static ledmap_t nt1500_std = { + 0x007, 0x000, 0x001, 0x004, 0x004, 0x004, 0x004, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x004, 0x002, 0x000, 0x007, 0x000, + 0x002, 0x002, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nt1500_def = { + 0x000, 0x000, 0x000, 0x001, +}; + +static void +nt1500_set(unsigned long bits) +{ + * (volatile char *) NETtel_LEDADDR = (~bits & 0x7); +} + +/****************************************************************************/ +#endif /* defined(CONFIG_NETtel) && defined(CONFIG_M5206e) */ +/****************************************************************************/ +#ifdef CONFIG_eLIA +/****************************************************************************/ +/* + * For the eLIA, only 2 LED's. + * + * LED - HEARTBEAT USER + * HEX - 2 1 + */ + +#ifdef CONFIG_COLDFIRE +#include +#include +#endif +#include + +static ledmap_t elia_std = { + 0x003, 0x000, 0x002, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x002, 0x001, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t elia_def = { + 0x000, 0x000, 0x000, 0x002, +}; + +static void +elia_set(unsigned long bits) +{ + unsigned long flags; + + save_flags(flags); cli(); + mcf_setppleds(0x3000, ~(bits << 12) & 0x3000); + restore_flags(flags); +} + +/****************************************************************************/ +#endif /* CONFIG_eLIA */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_AMDSC520) +/****************************************************************************/ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_CHINOOK) +/* + * Here is the definition of the LED's on the 6wind Chinook circuit board + * as per the LED order from left to right. These probably don't + * correspond to any known enclosure. + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 + * HEX - 0001 0400 0008 0010 0800 0020 0040 0080 0100 0200 + * + * Sync LEDs - Activity Link + * HEX - 04000000 08000000 + */ +static ledmap_t nettel_std = { + 0x0c000ff9, 0x00000001, 0x00000400, 0x00000040, 0x00000040, + 0x04000000, 0x04000000, 0x00000010, 0x00000008, 0x00000020, + 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000028, 0x00000810, 0x00000200, 0x00000bf8, 0x00000820, + 0x00000000, 0x08000000, 0x00000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static leddef_t nettel_def = { + 0x0000, 0x0001, 0x0000, 0x0400, +}; + +#elif defined(CONFIG_SNAPGEAR) +/* + * Here is the definition of the LED's on the SnapGear x86 circuit board + * as per the labels next to them. + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 + * HEX - 001 002 004 008 010 020 040 100 080 200 + */ +static ledmap_t nettel_std = { + 0x3ff, 0x001, 0x002, 0x080, 0x080, 0x040, 0x040, 0x010, 0x010, 0x020, + 0x020, 0x000, 0x000, 0x000, 0x000, 0x048, 0x030, 0x200, 0x3fc, 0x004, + 0x000, 0x000, 0x100, 0x008, 0x004, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nettel_def = { + 0x0000, 0x0001, 0x0000, 0x0002, +}; + +/* + * Here is the definition of the LED's on the SnapGear x86 circuit board + * as per the labels next to them. This is for the old enclosure. + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 + * HEX - 001 002 004 008 010 020 040 100 080 200 + */ +static ledmap_t nettel_old = { + 0x3ff, 0x002, 0x001, 0x080, 0x080, 0x040, 0x040, 0x010, 0x010, 0x020, + 0x020, 0x000, 0x000, 0x000, 0x000, 0x048, 0x030, 0x200, 0x3fc, 0x004, + 0x000, 0x000, 0x100, 0x008, 0x004, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nettel_def_old = { + 0x0000, 0x0002, 0x0000, 0x0001, +}; + +#elif defined(CONFIG_SITECTRLER) +/* + * Here it the definition of the LED's on the SiteController circuit board + * as per the labels next to them. (D9 and D10 are not software controlled) + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 + * HEX - 0001 0002 0004 0008 0010 0020 0040 0080 + */ +static ledmap_t nettel_std = { + 0x10fd,0x0001,0x1000,0x0004,0x0004,0x0008,0x0008,0x0040,0x0040,0x0080, + 0x0080,0x0000,0x0000,0x0000,0x0000,0x00cc,0x0030,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1000, + 0x0000,0x0000,0x0000,0x0000 +}; + +static leddef_t nettel_def = { + 0x0000, 0x0001, 0x0000, 0x1000, +}; + +#elif defined(CONFIG_ADTRAN_ADVANTA) +/* + * Here is the definition of the LED's on the Adtran Advanta3110 circuit + * board as per the labels next to them. + * The lower 8 bits are for IO port 0x300. + * The upper 4 bits are for PIO31-28. + * + * LED - D1 D2 D3 D4 D7 D8 D15green D15red D16green D16red + * HEX - 01 02 04 08 40 80 10000000 40000000 20000000 80000000 + */ +static ledmap_t nettel_std = { + 0xf00000cf, 0x00000000, 0x20000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000002, 0x00000001, 0x00000008, + 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000009, 0x00000006, 0x10000000, 0x100000cf, 0x0000000c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000080, 0x00000040, 0x00000001, 0x00000002, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static leddef_t nettel_def = { + 0, 0, 0, 0x20000000, +}; + +#else +/* + * Here is the definition of the LED's on the x86 NETtel circuit board + * as per the labels next to them. + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 + * HEX - 001 002 004 008 010 020 040 100 080 200 + */ +static ledmap_t nettel_std = { + 0x3ff, 0x002, 0x001, 0x100, 0x100, 0x080, 0x080, 0x010, 0x008, 0x040, + 0x020, 0x000, 0x000, 0x000, 0x000, 0x048, 0x030, 0x200, 0x3fc, 0x004, + 0x000, 0x000, 0x004, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t nettel_def = { + 0x0000, 0x0002, 0x0000, 0x0001, +}; + +#endif + +static volatile unsigned long *ledman_ledp; + +static void nettel_set(unsigned long bits) +{ +#ifdef CONFIG_ADTRAN_ADVANTA + outb(~bits, 0x300); + *ledman_ledp = (*ledman_ledp & 0x0fffffff) | (~bits & 0xf0000000); +#else + *ledman_ledp = (*ledman_ledp & ~ nettel_std[LEDMAN_ALL]) + | (~bits & nettel_std[LEDMAN_ALL]); +#endif +} + +static irqreturn_t ledman_interrupt(int irq, void *dev_id) +{ + ledman_signalreset(); + return IRQ_HANDLED; +} + +static void ledman_initarch(void) +{ + volatile unsigned char *mmcrp; + + /* Map the CPU MMCR register for access */ + mmcrp = (volatile unsigned char *) ioremap(0xfffef000, 4096); + +#ifdef CONFIG_ADTRAN_ADVANTA + /* Enable the PIO for the PWR and VPN LEDs */ + *(volatile unsigned short *)(mmcrp + 0xc22) &= 0x0fff; + *(volatile unsigned short *)(mmcrp + 0xc2c) |= 0xf000; + + /* Enable GPIRQ2, low-to-high transitions, map to IRQ12 */ + *(volatile unsigned short *)(mmcrp + 0xc22) |= 0x0020; + *(volatile unsigned long *)(mmcrp + 0xd10) |= 0x0004; + *(mmcrp + 0xd52) = 0x07; +#endif + + ledman_ledp = (volatile unsigned long *) (mmcrp + 0xc30); + + /* Setup extern "factory default" switch on IRQ12 */ + if (request_irq(12, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ12 for ERASE witch\n"); + else + printk("LED: registered ERASE switch on IRQ12\n"); +} + +/****************************************************************************/ +#endif /* CONFIG_AMDSC520 */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_GEODE) +/****************************************************************************/ + +#include + +/* + * Construct a mapping from virtual LED to gpio bit and bank. + */ +struct gpiomap { + unsigned int bank; + unsigned long bit; +}; + +#if defined(CONFIG_REEFEDGE) || defined(CONFIG_SE5000) +/* + * Definition of the LED's on the GEODE SC1100 ReefEdfe circuit board, + * as per the labels next to them. + * + * LED - D20 D19 D18 D16 + * GPIO BIT - 38 18 40 37 + * VIRTNUM - 0x8 0x4 0x2 0x1 + */ +#define GPIO0_OFF 0x00040000 +#define GPIO1_OFF 0x00000160 + +static ledmap_t nettel_std = { + 0x00f, 0x001, 0x002, 0x000, 0x000, 0x000, 0x000, 0x004, + 0x004, 0x008, 0x008, 0x000, 0x000, 0x000, 0x000, 0x004, + 0x008, 0x000, 0x00e, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000 +}; + +static struct gpiomap iomap[] = { + /* VIRT 0x1 */ { 1, 0x00000020 }, + /* VIRT 0x2 */ { 1, 0x00000100 }, + /* VIRT 0x4 */ { 0, 0x00040000 }, + /* VIRT 0x8 */ { 1, 0x00000040 }, +}; + +#elif defined(CONFIG_SE2910) +/* + * Definition of the LED's on the SnapGear SE2910 boards. + * + * LED - D2 D4 D6 D11 D13 D18 D20 D22 D25 D28 + * GPIO BIT - 2 3 17 0 36 47 39 40 18 38 + * VIRTNUM - 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 + */ +#define GPIO0_OFF 0x0006000d +#define GPIO1_OFF 0x000081d0 + +static ledmap_t nettel_std = { + 0x3ff, 0x001, 0x002, 0x080, 0x080, 0x080, 0x080, 0x010, + 0x008, 0x040, 0x020, 0x200, 0x200, 0x200, 0x200, 0x30c, + 0x0f0, 0x000, 0x3fc, 0x004, 0x000, 0x000, 0x004, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000 +}; + +static struct gpiomap iomap[] = { + /* VIRT 0x1 */ { 0, (1 << (02 - 00)) }, + /* VIRT 0x2 */ { 0, (1 << (03 - 00)) }, + /* VIRT 0x4 */ { 0, (1 << (17 - 00)) }, + /* VIRT 0x8 */ { 0, (1 << (00 - 00)) }, + /* VIRT 0x10 */ { 1, (1 << (36 - 32)) }, + /* VIRT 0x20 */ { 1, (1 << (47 - 32)) }, + /* VIRT 0x40 */ { 1, (1 << (39 - 32)) }, + /* VIRT 0x80 */ { 1, (1 << (40 - 32)) }, + /* VIRT 0x100 */ { 0, (1 << (18 - 00)) }, + /* VIRT 0x200 */ { 1, (1 << (38 - 32)) }, +}; + +#else +/* + * Definition of the LED's on the SnapGear GEODE board. + * + * LED - D11 D12 D13 D14 D15 D16 D17 D18 D19 D20 + * GPIO BIT - 32 33 34 35 36 37 39 40 18 38 + * VIRTNUM - 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 + */ +#define GPIO0_OFF 0x00040000 +#define GPIO1_OFF 0x000001ff + +static ledmap_t nettel_std = { + 0x3ff, 0x001, 0x002, 0x080, 0x080, 0x080, 0x080, 0x010, + 0x008, 0x040, 0x020, 0x200, 0x200, 0x200, 0x200, 0x30c, + 0x0f0, 0x000, 0x3fc, 0x004, 0x000, 0x000, 0x004, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000 +}; + +static struct gpiomap iomap[] = { + /* VIRT 0x1 */ { 1, 0x00000001 }, + /* VIRT 0x2 */ { 1, 0x00000002 }, + /* VIRT 0x4 */ { 1, 0x00000004 }, + /* VIRT 0x8 */ { 1, 0x00000008 }, + /* VIRT 0x10 */ { 1, 0x00000010 }, + /* VIRT 0x20 */ { 1, 0x00000020 }, + /* VIRT 0x40 */ { 1, 0x00000080 }, + /* VIRT 0x80 */ { 1, 0x00000100 }, + /* VIRT 0x100 */ { 0, 0x00040000 }, + /* VIRT 0x200 */ { 1, 0x00000040 }, +}; + +#endif /* !CONFIG_REEFEDGE && !CONFIG_SE5000 */ + +#define GPIO_SIZE (sizeof(iomap) / sizeof(*iomap)) + +static leddef_t nettel_def = { + 0x0000, 0x0001, 0x0000, 0x0002, +}; + + +static void nettel_set(unsigned long bits) +{ + unsigned int gpio[2]; + unsigned int i, mask; + + gpio[0] = GPIO0_OFF; + gpio[1] = GPIO1_OFF; + + for (i = 0, mask = 0x1; (i < GPIO_SIZE); i++, mask <<= 1) { + if (bits & mask) + gpio[iomap[i].bank] &= ~iomap[i].bit; + } + + outl(gpio[0], 0x6400); + outl(gpio[1], 0x6410); +} + +static int ledman_button; +static struct timer_list ledman_timer; + +static void ledman_buttonpoll(unsigned long arg) +{ + if (inl(0x6404) & 0x0002) { + if (ledman_button == 0) { + printk("LEDMAN: reset button pushed!\n"); + ledman_signalreset(); + } + ledman_button = 1; + } else { + ledman_button = 0; + } + + /* Re-arm timer interrupt. */ + mod_timer(&ledman_timer, jiffies + HZ/25); +} + +static void ledman_initarch(void) +{ + init_timer(&ledman_timer); + ledman_timer.function = ledman_buttonpoll; + ledman_timer.data = 0; + mod_timer(&ledman_timer, jiffies + HZ/25); +} + +/****************************************************************************/ +#endif /* CONFIG_GEODE */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_SH_KEYWEST) || defined(CONFIG_SH_BIGSUR) +/****************************************************************************/ +/* + * Here it the definition of the how we use the 8 segment LED display on + * the Hitachi Keywest + * + * LED - LD0 LD1 LD2 LD3 LD4 LD5 LD6 LD7 + * HEX - 001 002 004 008 010 020 040 080 + * HB CNT L1R L1T L2R L2T COM VPN + * + */ + +#include + +#define KEYWEST_NUM_LEDS 8 + +#if defined(CONFIG_SH_BIGSUR) +#define LED_BASE 0xb1fffe00 +#define LED_ADDR(x) (LED_BASE+((x)<<2)) +#else +#define LED_BASE 0xb1ffe000 +#define LED_ADDR(x) (LED_BASE+(x)) +#endif + +static ledmap_t keywest_std = { + 0x0ff, 0x000, 0x001, 0x040, 0x040, 0x040, 0x040, 0x004, 0x008, 0x010, + 0x020, 0x000, 0x000, 0x000, 0x000, 0x054, 0x02a, 0x080, 0x07e, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x002, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t keywest_def = { + 0x000, 0x000, 0x000, 0x001, +}; + +static struct keywest_led_value { + int count; + int max; + int prev; + unsigned char disp; +} keywest_led_values[KEYWEST_NUM_LEDS][2]; + + +struct keywest_font_s { + unsigned char row[7]; +} keywest_font[] = { + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, /* bar 0 */ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f }}, /* bar 1 */ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f }}, /* bar 2 */ + {{ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f }}, /* bar 3 */ + {{ 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f }}, /* bar 4 */ + {{ 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }}, /* bar 5 */ + {{ 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }}, /* bar 6 */ + {{ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }}, /* bar 7 */ + {{ 0x00, 0x0a, 0x1f, 0x1f, 0x0e, 0x04, 0x00 }}, /* heart */ + {{ 0x08, 0x14, 0x14, 0x1c, 0x1c, 0x1c, 0x1c }}, /* vpn locked */ + {{ 0x02, 0x05, 0x05, 0x1c, 0x1c, 0x1c, 0x1c }}, /* vpn unlocked */ +}; + +static unsigned int keywest_old_cntx = 0; + +/* + * program up some display bars + */ + +static void ledman_initkeywest() +{ + int i, j; + + for (i = 0; i < sizeof(keywest_font) / sizeof(struct keywest_font_s); i++) { + * (unsigned char *)(LED_ADDR(0x20)) = i; + for (j = 0; j < 7; j++) + * (unsigned char *)(LED_ADDR(0x28+j)) = keywest_font[i].row[j]; + } + keywest_old_cntx = kstat.context_swtch; +} + +/* + * We just rip through and write all LED 'disp' chars each tick. + */ + +static void keywest_set(unsigned long bits) +{ + int i, alt; + for (i = 0; i < KEYWEST_NUM_LEDS; i++) { + alt = (leds_alt & (1 << i)) ? 1 : 0; + * (unsigned char *)(LED_ADDR(0x38+i)) = keywest_led_values[i][alt].disp; + } +} + +static int +keywest_bits(unsigned long cmd, unsigned long bits) +{ + ledmode_t *lmp = &led_mode[current_mode]; + int alt, i; + unsigned long new_alt; + + alt = (cmd & LEDMAN_CMD_ALTBIT) ? 1 : 0; + + switch (cmd & ~LEDMAN_CMD_ALTBIT) { + case LEDMAN_CMD_SET: + bits &= ~(leds_flash[alt]|leds_on[alt]|leds_off[alt]); + for (i = 0; i < KEYWEST_NUM_LEDS; i++) + if (bits & (1 << i)) + keywest_led_values[i][alt].count++; + break; + case LEDMAN_CMD_ON: + leds_on[alt] |= bits; + leds_off[alt] &= ~bits; + leds_flash[alt] &= ~bits; + (*lmp->tick)(); + break; + case LEDMAN_CMD_OFF: + leds_on[alt] &= ~bits; + leds_off[alt] |= bits; + leds_flash[alt] &= ~bits; + (*lmp->tick)(); + break; + case LEDMAN_CMD_FLASH: + leds_on[alt] &= ~bits; + leds_off[alt] &= ~bits; + leds_flash[alt] |= bits; + break; + case LEDMAN_CMD_RESET: + leds_on[alt] = (leds_on[alt] &~bits) | (bits&lmp->def[LEDS_ON]); + leds_off[alt] = (leds_off[alt] &~bits) | (bits&lmp->def[LEDS_OFF]); + leds_flash[alt] = (leds_flash[alt]&~bits) | (bits&lmp->def[LEDS_FLASH]); + memset(keywest_led_values, 0, sizeof(keywest_led_values)); + break; + case LEDMAN_CMD_ALT_ON: + new_alt = (bits & ~leds_alt); + leds_alt |= bits; + /* + * put any newly alt'd bits into a default state + */ + (*lmp->bits)(LEDMAN_CMD_RESET | LEDMAN_CMD_ALTBIT, new_alt); + for (i = 0; i < 32; i++) + if (bits & (1 << i)) + leds_alt_cnt[i]++; + break; + case LEDMAN_CMD_ALT_OFF: + for (i = 0; i < 32; i++) + if ((bits & (1 << i)) && leds_alt_cnt[i]) { + leds_alt_cnt[i]--; + if (leds_alt_cnt[i] == 0) + leds_alt &= ~(1 << i); + } + break; + default: + return(-EINVAL); + } + return(0); +} + +static void +keywest_tick(void) +{ + ledmode_t *lmp = &led_mode[current_mode]; + int alt, i; + static int flash_on = 0; + struct keywest_led_value *led_value; + + /* + * we take over the second LED as a context switch indicator + */ + keywest_led_values[1][0].count = kstat.context_swtch - keywest_old_cntx; + keywest_old_cntx = kstat.context_swtch; + + for (i = 0; i < KEYWEST_NUM_LEDS; i++) { + alt = (leds_alt >> i) & 1; + led_value = &keywest_led_values[i][alt]; + if (leds_off[alt] & (1 << i)) { + if ((1 << i) == 0x080) /* VPN unlock */ + led_value->disp = 0x8a; + else + led_value->disp = 0x20; + } else if (leds_on[alt] & (1 << i)) { + if ((1 << i) == 0x080) /* VPN lock */ + led_value->disp = 0x89; + else + led_value->disp = 0x87; + } else if (leds_flash[alt] & (1 << i)) { + if ((flash_on % 6) >= 3) { + if ((1 << i) == 0x001) /* heart beat */ + led_value->disp = 0x88; + else + led_value->disp = 0x87; + } else + led_value->disp = 0x20; + } else { + int val; + + if (led_value->count > led_value->max) + led_value->max = led_value->count; + + val = (led_value->prev + led_value->count) / 2; + led_value->prev = val; + + val = (val * 7) / led_value->max; + if (val == 0 && led_value->count) + val = 1; + led_value->disp = 0x80 + (val & 0x7); + led_value->count = 0; + /* degrade the maximum over time (except load) */ + if (i != 1) + led_value->max = (led_value->max * 9)/10; + } + } + flash_on++; + (*lmp->set)(0); +} + +/****************************************************************************/ +#endif /* CONFIG_SH_KEYWEST */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_MACH_MONTEJADE) || defined(CONFIG_MACH_IXDPG425) || \ + defined(CONFIG_MACH_SE5100) +/****************************************************************************/ + +#include +#include +#include + +/* + * Here is the definition of the LED's on the Intel/MonteJade platform. + * LED D7 is not visible on the front panel, so not much point using it... + * + * LED - D1 D2 D3 D4 D16 D17 D18 D23 + * HEX - 80 40 20 10 08 04 02 01 + */ +static ledmap_t montejade_std = { + 0xff, 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x20, 0xfc, 0x10, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static leddef_t montejade_def = { + 0x0000, 0x0000, 0x0000, 0x0001, +}; + + +static volatile unsigned char *ledman_cs2; + +static void ledman_interrupt(int irq, void *dev_id) +{ + ledman_signalreset(); +} + +static void montejade_set(unsigned long bits) +{ + *ledman_cs2 = ~bits; +} + +static struct timer_list montejade_wdt; + +static void montejade_wdtpoll(unsigned long arg) +{ + *IXP4XX_GPIO_GPOUTR ^= 0x400; + + /* Re-arm timer interrupt. */ + mod_timer(&montejade_wdt, jiffies + HZ/10); +} + +static void montejade_wdtinit(void) +{ + /* Configure GPIO10 as an output to kick watchdog */ + gpio_line_config(10, IXP4XX_GPIO_OUT); + + /* Setup timer poll, 10 times a second should be good enough */ + init_timer(&montejade_wdt); + montejade_wdt.function = montejade_wdtpoll; + montejade_wdt.data = 0; + mod_timer(&montejade_wdt, jiffies + HZ/10); +} + +static void ledman_initarch(void) +{ + /* Configure CS2 for operation, 8bit and writable will do */ + *IXP4XX_EXP_CS2 = 0xbfff0003; + + /* Map the LED chip select address space */ + ledman_cs2 = (volatile unsigned char *) ioremap(IXP4XX_EXP_BUS_CS2_BASE_PHYS, 512); + *ledman_cs2 = 0xffffffff; + + /* Configure GPIO9 as interrupt input (ERASE switch) */ + gpio_line_config(9, (IXP4XX_GPIO_IN | IXP4XX_GPIO_FALLING_EDGE)); + + if (request_irq(26, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ26 for ERASE witch\n"); + else + printk("LED: registered ERASE switch on IRQ26\n"); + + montejade_wdtinit(); +} + +/****************************************************************************/ +#endif /* CONFIG_MACH_MONTEJADE || CONFIG_MACH_IXDPG425 || CONFIG_MACH_SE5100 */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_ARCH_SE4000) || defined(CONFIG_MACH_ESS710) || \ + defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \ + defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SG640) || \ + defined(CONFIG_MACH_SG720) || defined(CONFIG_MACH_SG590) || \ + defined(CONFIG_MACH_SG8100) +/****************************************************************************/ + +#include +#include +#include + +#if defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_SG720) +/* + * Here is the definition of the LED's on the SnapGear/ESS710 circuit board + * as per the labels next to them. + * + * LED - D1 D3 D4 D5 + * HEX - 004 008 010 020 + * F/OVER H/A ONLINE H/B + */ +static ledmap_t snapgear425_std = { + 0x03c, 0x000, 0x020, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x024, 0x018, 0x000, 0x03c, 0x000, + 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x004, 0x008 +}; + +static leddef_t snapgear425_def = { + 0x0000, 0x0000, 0x0000, 0x0020, +}; + +#define LEDMASK 0x3c + +#elif defined(CONFIG_MACH_SG640) +/* + * Here is the definition of the LED's on the SnapGear/SG640 circuit board + * as per the labels next to them. + * + */ + +#define LED_D1_UPPER 0x08 +#define LED_D1_LOWER 0x10 +#define LED_D2_UPPER 0x20 +#define LED_D2_LOWER 0x04 +#define LEDMASK 0x3c + +static ledmap_t snapgear425_std = { + [LEDMAN_ALL] = LEDMASK, + [LEDMAN_POWER] = LED_D1_LOWER, + [LEDMAN_HEARTBEAT] = LED_D1_UPPER, + [LEDMAN_VPN] = LED_D2_LOWER, + [LEDMAN_ONLINE] = LED_D2_UPPER, + [LEDMAN_NVRAM_1] = LED_D1_LOWER | LED_D2_UPPER, + [LEDMAN_NVRAM_2] = LED_D2_LOWER | LED_D1_UPPER, + [LEDMAN_LAN1_DHCP] = LED_D2_LOWER | LED_D2_UPPER, + [LEDMAN_LAN2_DHCP] = LED_D2_LOWER | LED_D2_UPPER, +}; + +static leddef_t snapgear425_def = { + [LEDS_ON] = LED_D1_LOWER, + [LEDS_FLASH] = LED_D1_UPPER, +}; + +#elif defined(CONFIG_MACH_SG565) + +/* + * Here is the definition of the LEDs on the CyberGuard/SG565, + * as per the labels next to them. + * + * LED - D2 D3 D4 D5 D6 D7 D8 + * HEX - 0004 0008 0010 0020 0040 0080 0400 + */ +static ledmap_t snapgear425_std = { + [LEDMAN_ALL] = 0x4fc, + [LEDMAN_HEARTBEAT] = 0x004, + [LEDMAN_COM1_RX] = 0x040, + [LEDMAN_COM1_TX] = 0x040, + [LEDMAN_LAN1_RX] = 0x008, + [LEDMAN_LAN1_TX] = 0x008, + [LEDMAN_LAN2_RX] = 0x008, + [LEDMAN_LAN2_TX] = 0x008, + [LEDMAN_USB1_RX] = 0x010, + [LEDMAN_USB1_TX] = 0x010, + [LEDMAN_USB2_RX] = 0x010, + [LEDMAN_USB2_TX] = 0x010, + [LEDMAN_NVRAM_1] = 0x48c, + [LEDMAN_NVRAM_2] = 0x070, + [LEDMAN_VPN] = 0x400, + [LEDMAN_LAN1_DHCP] = 0x4fc, + [LEDMAN_ONLINE] = 0x080, + [LEDMAN_LAN3_RX] = 0x020, + [LEDMAN_LAN3_TX] = 0x020, +}; + +static leddef_t snapgear425_def = { + [LEDS_FLASH] = 0x004, +}; + +#define LEDMASK 0x04fc + +#elif defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) +/* + * Here is the definition of the LEDs on the CyberGuard/SG560 + * and CyberGuard/SG580, as per the labels next to them. + * + * LED - D2 D3 D4 D5 D6 D7 D8 + * HEX - 0004 0008 0010 0400 0040 0020 0080 + */ +static ledmap_t snapgear425_std = { + 0x4fc, 0x000, 0x004, 0x040, 0x040, 0x040, 0x040, 0x008, 0x008, 0x010, + 0x010, 0x000, 0x000, 0x000, 0x000, 0x0ac, 0x450, 0x080, 0x4fc, 0x000, + 0x000, 0x000, 0x020, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x400 +}; + +static leddef_t snapgear425_def = { + 0x0000, 0x0000, 0x0000, 0x0004, +}; + +#define LEDMASK 0x04fc + +#elif defined(CONFIG_MACH_SG590) +/* + * Here is the definition of the LEDs on the TAMS/TVR. + */ +#define LED_D2 0x80 +#define LED_D3 0x40 +#define LED_D4 0x20 +#define LED_D5 0x10 +#define LED_D6 0x08 +#define LED_D7 0x04 +#define LEDMASK 0xfc + +static ledmap_t snapgear425_std = { + [LEDMAN_ALL] = LEDMASK, + [LEDMAN_HEARTBEAT] = LED_D2, + [LEDMAN_LAN1_RX] = LED_D3, + [LEDMAN_LAN1_TX] = LED_D3, + [LEDMAN_LAN2_RX] = LED_D4, + [LEDMAN_LAN2_TX] = LED_D4, + [LEDMAN_VPN_RX] = LED_D5, + [LEDMAN_VPN_TX] = LED_D5, + [LEDMAN_ONLINE] = LED_D6, + [LEDMAN_VPN] = LED_D7, + [LEDMAN_NVRAM_1] = LED_D4 | LED_D5, + [LEDMAN_NVRAM_2] = LED_D2 | LED_D3 | LED_D6 | LED_D7, + [LEDMAN_LAN1_DHCP] = LEDMASK, +}; + +static leddef_t snapgear425_def = { + [LEDS_FLASH] = LED_D2, +}; + +#elif defined(CONFIG_MACH_SG8100) + +/* + * Here is the definition of the LEDs on the SG8100 + * as per the labels next to them. + * + * LED - D1 D2 D3 D4 D5 D6 D7 D8 + * HEX - 0004 0008 0010 0020 0040 0080 0400 0800 + */ +static ledmap_t snapgear425_std = { + [LEDMAN_ALL] = 0xcfc, + [LEDMAN_HEARTBEAT] = 0x004, + [LEDMAN_COM1_RX] = 0x040, + [LEDMAN_COM1_TX] = 0x040, + [LEDMAN_LAN1_RX] = 0x008, + [LEDMAN_LAN1_TX] = 0x008, + [LEDMAN_LAN2_RX] = 0x008, + [LEDMAN_LAN2_TX] = 0x008, + [LEDMAN_USB1_RX] = 0x010, + [LEDMAN_USB1_TX] = 0x010, + [LEDMAN_USB2_RX] = 0x010, + [LEDMAN_USB2_TX] = 0x010, + [LEDMAN_NVRAM_1] = 0xc0c, + [LEDMAN_NVRAM_2] = 0x0f0, + [LEDMAN_VPN] = 0x400, + [LEDMAN_LAN1_DHCP] = 0xcfc, + [LEDMAN_ONLINE] = 0x080, + [LEDMAN_LAN3_RX] = 0x020, + [LEDMAN_LAN3_TX] = 0x020, +}; + +static leddef_t snapgear425_def = { + [LEDS_FLASH] = 0x004, +}; + +#define LEDMASK 0x0cfc + +#else + +/* + * Here is the definition of the LEDs on the SnapGear/SE4000, as per the + * labels next to them. LED D7 is not visible on the front panel, so not + * much point using it... + * + * LED - D1 D3 D4 D5 D6 D7 + * HEX - 004 008 010 020 040 080 + */ +static ledmap_t snapgear425_std = { + 0x0fc, 0x000, 0x004, 0x008, 0x008, 0x008, 0x008, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x028, 0x010, 0x020, 0x0fc, 0x010, + 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t snapgear425_def = { + 0x0000, 0x0000, 0x0000, 0x0004, +}; + +#define LEDMASK 0xfc + +#endif + +#if defined(CONFIG_MACH_SG720) || defined(CONFIG_MACH_SG590) +#define ERASEGPIO 10 +#define ERASEIRQ IRQ_IXP4XX_GPIO10 +#else +#define ERASEGPIO 9 +#define ERASEIRQ IRQ_IXP4XX_GPIO9 +#endif + + +static irqreturn_t ledman_interrupt(int irq, void *dev_id) +{ + ledman_signalreset(); + return IRQ_HANDLED; +} + +static void snapgear425_set(unsigned long bits) +{ + *IXP4XX_GPIO_GPOUTR = (*IXP4XX_GPIO_GPOUTR & ~LEDMASK) | (~bits & LEDMASK); +} + +static void ledman_initarch(void) +{ + /* Enable LED lines as outputs - do them all in one go */ + *IXP4XX_GPIO_GPOER &= ~LEDMASK; + + /* Configure GPIO9 as interrupt input (ERASE switch) */ + gpio_line_config(ERASEGPIO, IXP4XX_GPIO_IN); + set_irq_type(ERASEIRQ, IRQT_FALLING); + +#if !defined(CONFIG_MACH_SG720) && !defined(CONFIG_MACH_SG590) + /* De-assert reset for the hub/switch - just in case... */ + gpio_line_config(13, IXP4XX_GPIO_OUT); + gpio_line_set(13, 1); +#endif + + if (request_irq(ERASEIRQ, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ%d for ERASE witch\n", ERASEIRQ); + else + printk("LED: registered ERASE switch on IRQ%d\n", ERASEIRQ); +} + +/****************************************************************************/ +#endif /* CONFIG_ARCH_SE4000 || CONFIG_MACH_ESS710 || CONFIG_MACH_SG560 || CONFIG_MACH_SG565 || CONFIG_MACH_SG580 || CONFIG_MACH_SG640 || CONFIG_MACH_SG720 || CONFIG_MACH_SG590 || CONFIG_MACH_SG8100 */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_MACH_IVPN) +/****************************************************************************/ + +#include +#include +#include + +/* + * There is 2 LED banks on the iVPN. But really there is 4 LEDs, 2 green + * and 2 red. They are connected to gpio lines, with the mapping: + * + * GPIO - 12 13 2 11 + * LED - G0 R0 G1 R1 + * + * But... + * + * I have virtualized the bits in the ledmap, since the iVPN led + * functionality is a little weird, and cannot be displayed by just + * setting the bits. + */ + +#define BIT_HEARTBEAT 0x1 +#define BIT_LANLINK 0x2 +#define BIT_LANACTIVITY 0x4 +#define BIT_WANLINK 0x8 +#define BIT_WANACTIVITY 0x10 +#define BIT_WIFLINK 0x20 +#define BIT_WIFACTIVITY 0x40 +#define BIT_VPNLINK 0x80 +#define BIT_VPNACTIVITY 0x100 + +static ledmap_t ivpn_std = { + 0x1ff, 0x000, 0x001, 0x000, 0x000, 0x000, 0x000, 0x004, 0x004, 0x010, + 0x010, 0x000, 0x000, 0x000, 0x000, 0x00a, 0x088, 0x080, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x002, 0x008, 0x100, 0x100, 0x000, 0x000, 0x040, + 0x040, 0x020, 0x000, 0x000 +}; + +static leddef_t ivpn_def = { + 0x0000, 0x0002, 0x0000, 0x0001, +}; + + +static irqreturn_t ledman_interrupt(int irq, void *dev_id) +{ + ledman_signalreset(); + return IRQ_HANDLED; +} + +static void ivpn_set(unsigned long bits) +{ + unsigned long flags; + unsigned int wanbit, val = 0; + static unsigned int lancnt = 0; + static unsigned int wancnt = 0; + + if (bits & BIT_LANLINK) { + if ((bits & BIT_LANACTIVITY) || lancnt) { + if (lancnt++ > 4) { + val |= 0x1; + if (lancnt > 8) + lancnt = 0; + } + } else { + val |= 0x1; + } + } else { + val |= 0x2; + } + if (bits & (BIT_WANLINK | BIT_WIFLINK)) { + wanbit = (bits & BIT_VPNLINK) ? 0x4 : 0x8; + if ((bits & (BIT_WANACTIVITY | BIT_WIFACTIVITY)) || wancnt) { + if (wancnt++ > 4) { + val |= wanbit; + if (wancnt > 8) + wancnt = 0; + } + } else { + val |= wanbit; + } + } + + save_flags(flags); cli(); + gpio_line_set(2, val & 0x4 ? 0 : 1); + gpio_line_set(11, val & 0x8 ? 0 : 1); + gpio_line_set(12, val & 0x1 ? 0 : 1); + gpio_line_set(13, val & 0x2 ? 0 : 1); + restore_flags(flags); +} + +static void ledman_initarch(void) +{ +#if 0 + /* Enabled second ethernet port */ + gpio_line_config(3, IXP4XX_GPIO_OUT); + gpio_line_set(3, 0); +#endif + /* Set up GPIO lines to allow access to LEDs. */ + gpio_line_set(2, 1); + gpio_line_set(11, 1); + gpio_line_set(12, 1); + gpio_line_set(13, 1); + gpio_line_config(2, IXP4XX_GPIO_OUT); + gpio_line_config(11, IXP4XX_GPIO_OUT); + gpio_line_config(12, IXP4XX_GPIO_OUT); + gpio_line_config(13, IXP4XX_GPIO_OUT); + ivpnss_hwsetup(); + ivpnss_memmap(); + + /* Configure GPIO9 as interrupt input (ERASE switch) */ + gpio_line_config(9, (IXP4XX_GPIO_IN | IXP4XX_GPIO_FALLING_EDGE)); + + if (request_irq(26, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ26 for ERASE witch\n"); + else + printk("LED: registered ERASE switch on IRQ26\n"); +} + +/****************************************************************************/ +#endif /* CONFIG_MACH_IVPN */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_ARCH_KS8695) +/****************************************************************************/ + +#include +#include +#include + +/* + * Here is the definition of the LED's on the SnapGear/LITE3 circuit board, + * as per the labels next to them. There is only 2 software programmable + * LEDs, so this is pretty easy :-) + * + * LED - D1 D2 + * HEX - 002 004 + */ +static ledmap_t lite3_std = { + 0x006, 0x004, 0x002, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x002, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000 +}; + +static leddef_t lite3_def = { + 0x0000, 0x0004, 0x0000, 0x0002, +}; + +static volatile unsigned int *ledman_gpio; + +static irqreturn_t ledman_interrupt(int irq, void *dev_id) +{ + volatile unsigned int *intstatp; + + intstatp = (volatile unsigned int __force *) (KS8695_REG(KS8695_INT_STATUS)); + *intstatp |= 0x4; + + ledman_signalreset(); + return IRQ_HANDLED; +} + +static void lite3_set(unsigned long bits) +{ + *ledman_gpio = (*ledman_gpio & ~0x6) | (~bits & 0x6); +} + +static void ledman_initarch(void) +{ + volatile unsigned int *gpiop, *intenp; + + /* Enable LED lines as outputs */ + gpiop = (volatile unsigned int __force *) (KS8695_REG(KS8695_GPIO_MODE)); + *gpiop = (*gpiop | 0x6) & ~0x1; + + /* Turn LEDs off */ + ledman_gpio = (volatile unsigned int __force *) (KS8695_REG(KS8695_GPIO_DATA)); + *ledman_gpio = (*ledman_gpio & ~0x6); + + /* Configure GPIO0 as interrupt input (ERASE switch) */ + gpiop = (volatile unsigned int __force *) (KS8695_REG(KS8695_GPIO_CTRL)); + *gpiop = (*gpiop & ~0x7) | 0xc; + + intenp = (volatile unsigned int __force *) (KS8695_REG(KS8695_INT_ENABLE)); + *intenp |= 0x4; + + if (request_irq(2, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ2 for ERASE witch\n"); + else + printk("LED: registered ERASE switch on IRQ2\n"); +} + +/****************************************************************************/ +#endif /* CONFIG_ARCH_KS8695 */ +/****************************************************************************/ +/****************************************************************************/ +#if defined(CONFIG_ARCH_EP9312) +/****************************************************************************/ + +#include +#include +#include + +/* + * Here is the definition of the LED's on the Trusonic IPD Board + * + * It has no visible LED's, though it has provision for deug LED's, + * however, we need flatfsd support ;-) + */ +static ledmap_t ipd_std; +static leddef_t ipd_def; + +static void ipd_set(unsigned long bits) +{ +} + +static irqreturn_r ledman_interrupt(int irq, void *dev_id) +{ + while (inl(VIC1RAWINTR) & 0x1) + ; + ledman_signalreset(); + return IRQ_HANDLED; +} + +static void ledman_initarch(void) +{ + if (request_irq(32, ledman_interrupt, SA_INTERRUPT, "Erase", NULL)) + printk("LED: failed to register IRQ32 for ERASE witch\n"); + else + printk("LED: registered ERASE switch on IRQ32\n"); +} + +/****************************************************************************/ +#endif /* CONFIG_ARCH_EP9312 */ +/****************************************************************************/ diff --git a/drivers/char/m41t11m6.c b/drivers/char/m41t11m6.c new file mode 100644 index 00000000..f5db9661 --- /dev/null +++ b/drivers/char/m41t11m6.c @@ -0,0 +1,527 @@ +/*****************************************************************************/ + +/* + * m41t11m6.c -- driver for M41T11M6 Real Time Clock. + * + * (C) Copyright 2004-2005, Greg Ungerer + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*****************************************************************************/ + +/* + * Size of RTC region. 64 bytes total, the first 10 are the RTC. + */ +#define M41T11M6_MSIZE 0x3f + +/*****************************************************************************/ + +/* + * M41T11M6 defines. + */ +#define M41T11M6_ADDR 0xd0 /* IIC address of M41T11M6 device */ +#define M41T11M6_RD 1 /* Read bit command */ +#define M41T11M6_WR 0 /* Write bit command */ + +#define M41T11M6_SEC 0x00 /* Address of second register */ +#define M41T11M6_MIN 0x01 /* Address of minute register */ +#define M41T11M6_HOUR 0x02 /* Address of hour register */ +#define M41T11M6_WDAY 0x03 /* Address of day of week register */ +#define M41T11M6_MDAY 0x04 /* Address of day of month register */ +#define M41T11M6_MON 0x05 /* Address of month register */ +#define M41T11M6_YEAR 0x06 /* Address of year register */ +#define M41T11M6_FTOUT 0x07 /* Address of control register */ + +/*****************************************************************************/ +#ifdef CONFIG_MACH_IPD +/*****************************************************************************/ + +#include + +/* + * On the EP9312/IPD, the clock in on EGIO[1] and the data is on EGPIO[3] + */ +#define SDA 0x8 +#define SCL 0x2 +#define IN 0 +#define OUT 1 + +static void gpio_line_config(int line, int dir) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (dir == OUT) + outl(inl(GPIO_PADDR) | line, GPIO_PADDR); /* data is output */ + else + outl(inl(GPIO_PADDR) & ~line, GPIO_PADDR); /* data is input */ + restore_flags(flags); +} + +static void gpio_line_set(int line, int val) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (val) + outl(inl(GPIO_PADR) | line, GPIO_PADR); + else + outl(inl(GPIO_PADR) & ~line, GPIO_PADR); + restore_flags(flags); +} + +static inline void gpio_line_get(int line, int *val) +{ + *val = (inl(GPIO_PADR) & line) ? 1 : 0; +} + +/*****************************************************************************/ +#elif defined(CONFIG_MACH_CM41xx) || defined(CONFIG_MACH_CM4008) +/*****************************************************************************/ + +#include + +/* + * GPIO lines 6, 7 and 8 are used for the RTC. + */ +#define SDAT 6 /* SDA transmit */ +#define SDAR 7 /* SDA receiver */ +#define SCL 8 /* SCL - clock */ +#define SDA SDAR + +#define IN 0 +#define OUT 1 + +#define SDAT_B (1 << SDAT) +#define SDAR_B (1 << SDAR) +#define SCL_B (1 << SCL) + +static volatile unsigned int *gpdatap = (volatile unsigned int *) (IO_ADDRESS(KS8695_IO_BASE) + KS8695_GPIO_DATA); +static volatile unsigned int *gpmodep = (volatile unsigned int *) (IO_ADDRESS(KS8695_IO_BASE) + KS8695_GPIO_MODE); + +static inline void gpio_line_config(int line, int dir) +{ + if (line == SDA) { + if (dir == IN) + *gpdatap |= SDAT_B; + } + if (line == SCL) { + /* We do normal initialization for all GPIO bits here */ + *gpmodep |= SCL_B | SDAT_B; + *gpmodep &= ~SDAR_B; + } +} + +static inline void gpio_line_set(int line, int val) +{ + if (line == SCL) { + if (val) + *gpdatap |= SCL_B; + else + *gpdatap &= ~SCL_B; + } else { + if (val) + *gpdatap |= SDAT_B; + else + *gpdatap &= ~SDAT_B; + } +} + +static inline void gpio_line_get(int line, int *val) +{ + *val = (*gpdatap & SDAR_B) ? 1 : 0; +} + +/*****************************************************************************/ +#else +/*****************************************************************************/ + +/* + * The IIC lines to the M41T11M6 are GPIO lines from the IXP4xx. + * The clock line is on GPIO12, and the data line on GPIO11. + */ +#define SDA 11 +#define SCL 12 +#define IN IXP4XX_GPIO_IN +#define OUT IXP4XX_GPIO_OUT + +/*****************************************************************************/ +#endif +/*****************************************************************************/ + +static void gpio_line_config_slow(u8 line, u32 style) +{ + gpio_line_config(line, style); + udelay(10); +} + +static void gpio_line_set_slow(u8 line, int value) +{ + gpio_line_set(line, value); + udelay(10); +} + +static void gpio_line_get_slow(u8 line, int *value) +{ + gpio_line_get(line, value); + udelay(10); +} + +/*****************************************************************************/ + +void m41t11m6_readack(void) +{ + unsigned int ack; + + gpio_line_config_slow(SDA, IN); + gpio_line_set_slow(SCL, 1); + gpio_line_get_slow(SDA, &ack); + gpio_line_set_slow(SCL, 0); + gpio_line_config_slow(SDA, OUT); +} + +void m41t11m6_writeack(void) +{ + gpio_line_set_slow(SDA, 0); + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SCL, 0); +} + +void m41t11m6_sendbits(unsigned int val) +{ + int i; + + gpio_line_set_slow(SCL, 0); + for (i = 7; (i >= 0); i--) { + gpio_line_set_slow(SDA, ((val >> i) & 0x1)); + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SCL, 0); + } +} + +unsigned int m41t11m6_recvbits(void) +{ + unsigned int val, bit; + int i; + + gpio_line_set_slow(SCL, 0); + gpio_line_config_slow(SDA, IN); + for (i = 0, val = 0; (i < 8); i++) { + gpio_line_set_slow(SCL, 1); + gpio_line_get_slow(SDA, &bit); + val = (val << 1) | bit; + gpio_line_set_slow(SCL, 0); + } + + gpio_line_config_slow(SDA, OUT); + return val; +} + +/*****************************************************************************/ +DECLARE_MUTEX(m41t11m6_sem); + +/* + * The read byte sequenece is actually a write sequence followed + * by the read sequenece. The first write is to set the register + * address, and is a complete cycle itself. + */ +unsigned int m41t11m6_readbyte(unsigned int addr) +{ + unsigned int val; + + down(&m41t11m6_sem); +#if 0 + printk("m41t11m6_readbyte(addr=%x)\n", addr); +#endif + + /* Send start signal */ + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SDA, 1); + gpio_line_set_slow(SDA, 0); + + /* Send M41T11M6 device address byte, and write command for addr */ + m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_WR); + m41t11m6_readack(); + m41t11m6_sendbits(addr); + m41t11m6_readack(); + + /* Now send sequence to read bytes, starting with start signal */ + gpio_line_set_slow(SDA, 1); + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SDA, 1); + gpio_line_set_slow(SDA, 0); + + /* Send M41T11M6 device address byte, and read command for addr */ + m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_RD); + m41t11m6_writeack(); + val = m41t11m6_recvbits(); + + /* Send stop signal */ + gpio_line_set_slow(SDA, 0); + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SDA, 1); + + up(&m41t11m6_sem); + + return val; +} + +void m41t11m6_writebyte(unsigned int addr, unsigned int val) +{ + down(&m41t11m6_sem); +#if 0 + printk("m41t11m6_writebyte(addr=%x)\n", addr); +#endif + + /* Send start signal */ + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SDA, 1); + gpio_line_set_slow(SDA, 0); + + /* Send M41T11M6 device address byte, and write command */ + m41t11m6_sendbits(M41T11M6_ADDR | M41T11M6_WR); + m41t11m6_readack(); + + /* Send word address and data to write */ + m41t11m6_sendbits(addr); + m41t11m6_readack(); + m41t11m6_sendbits(val); + m41t11m6_readack(); + + /* Send stop signal */ + gpio_line_set_slow(SDA, 0); + gpio_line_set_slow(SCL, 1); + gpio_line_set_slow(SDA, 1); + + up(&m41t11m6_sem); +} + +/*****************************************************************************/ + +void m41t11m6_setup(void) +{ + down(&m41t11m6_sem); + + /* Initially set the IIC lines to be outputs from the IXP4xx */ + gpio_line_config(SCL, OUT); + gpio_line_config(SDA, OUT); + + /* Set IIC bus into idle mode */ + gpio_line_set(SCL, 1); + gpio_line_set(SDA, 1); + + up(&m41t11m6_sem); +} + +/*****************************************************************************/ + +int bcd2bin(int val) +{ + return ((((val & 0xf0) >> 4) * 10) + (val & 0xf)); +} + +int bin2bcd(int val) +{ + val &= 0xff; + return (((val / 10) << 4) + (val % 10)); +} + +/*****************************************************************************/ + +static ssize_t m41t11m6_read(struct file *fp, char __user *buf, size_t count, loff_t *ptr) +{ + int total; + +#if 0 + printk("m41t11m6_read(buf=%x,count=%d)\n", (int) buf, count); +#endif + + if (fp->f_pos >= M41T11M6_MSIZE) + return 0; + + if (count > (M41T11M6_MSIZE - fp->f_pos)) + count = M41T11M6_MSIZE - fp->f_pos; + + for (total = 0; (total < count); total++) + put_user(m41t11m6_readbyte(fp->f_pos + total), buf++); + + fp->f_pos += total; + return total; +} + +/*****************************************************************************/ + +static ssize_t m41t11m6_write(struct file *fp, const char __user *buf, size_t count, loff_t *ptr) +{ + int total; + char val; + +#if 0 + printk("m41t11m6_write(buf=%x,count=%d)\n", (int) buf, count); +#endif + + if (fp->f_pos >= M41T11M6_MSIZE) + return 0; + + if (count > (M41T11M6_MSIZE - fp->f_pos)) + count = M41T11M6_MSIZE - fp->f_pos; + + for (total = 0; (total < count); total++, buf++) { + get_user(val,buf); + m41t11m6_writebyte((fp->f_pos + total), val); + } + + fp->f_pos += total; + return total; +} + +/*****************************************************************************/ + +/* + * Do some consistency checks on the time. On first power up the + * RTC may contain completely bogus junk, this will clean it up. + * Just for good measure we do this when writing to the RTC as well. + */ + +static void m41t11m6_validatetime(struct rtc_time *rtime) +{ + if ((rtime->tm_year < 70) || (rtime->tm_year >= 200)) + rtime->tm_year = 70; + if ((rtime->tm_mon < 0) || (rtime->tm_mon >= 12)) + rtime->tm_mon = 0; + if ((rtime->tm_mday < 1) || (rtime->tm_mday > 31)) + rtime->tm_mday = 1; + if ((rtime->tm_wday < 0) || (rtime->tm_wday >= 7)) + rtime->tm_wday = 0; + if ((rtime->tm_hour < 0) || (rtime->tm_hour >= 24)) + rtime->tm_hour = 0; + if ((rtime->tm_min < 0) || (rtime->tm_min >= 60)) + rtime->tm_min = 0; + if ((rtime->tm_sec < 0) || (rtime->tm_sec >= 60)) + rtime->tm_sec = 0; +} + +/*****************************************************************************/ + +static void m41t11m6_readtime(struct rtc_time *rtime) +{ + memset(rtime, 0, sizeof(*rtime)); + rtime->tm_year = bcd2bin(m41t11m6_readbyte(M41T11M6_YEAR)) + + ((m41t11m6_readbyte(M41T11M6_HOUR) & 0x40) ? 100 : 0); + rtime->tm_mon = bcd2bin(m41t11m6_readbyte(M41T11M6_MON & 0x1f)) - 1; + rtime->tm_mday = bcd2bin(m41t11m6_readbyte(M41T11M6_MDAY & 0x3f)); + rtime->tm_wday = bcd2bin(m41t11m6_readbyte(M41T11M6_WDAY) & 0x7) - 1; + rtime->tm_hour = bcd2bin(m41t11m6_readbyte(M41T11M6_HOUR) & 0x3f); + rtime->tm_min = bcd2bin(m41t11m6_readbyte(M41T11M6_MIN) & 0x7f); + rtime->tm_sec = bcd2bin(m41t11m6_readbyte(M41T11M6_SEC) & 0x7f); +} + +/*****************************************************************************/ + +static void m41t11m6_settime(struct rtc_time *rtime) +{ + m41t11m6_writebyte(M41T11M6_YEAR, bin2bcd(rtime->tm_year)); + m41t11m6_writebyte(M41T11M6_MON, bin2bcd(rtime->tm_mon+1)); + m41t11m6_writebyte(M41T11M6_MDAY, bin2bcd(rtime->tm_mday)); + m41t11m6_writebyte(M41T11M6_WDAY, bin2bcd(rtime->tm_wday+1)); + m41t11m6_writebyte(M41T11M6_HOUR, bin2bcd(rtime->tm_hour) | + ((rtime->tm_year > 99) ? 0xc0 : 0x80)); + m41t11m6_writebyte(M41T11M6_MIN, bin2bcd(rtime->tm_min)); + m41t11m6_writebyte(M41T11M6_SEC, bin2bcd(rtime->tm_sec)); + m41t11m6_writebyte(M41T11M6_FTOUT, 0x90); +} + +/*****************************************************************************/ + +static int m41t11m6_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) +{ + struct rtc_time rtime; + +#if 0 + printk("m41t11m6_ioctl(cmd=%x,arg=%x)\n", cmd, arg); +#endif + + switch (cmd) { + + case RTC_RD_TIME: + m41t11m6_readtime(&rtime); + m41t11m6_validatetime(&rtime); + if (copy_to_user((void __user *) arg, &rtime, sizeof(rtime))) + return -EFAULT; + break; + + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EACCES; + m41t11m6_validatetime(&rtime); + if (copy_from_user(&rtime, (void __user *) arg, sizeof(rtime))) + return -EFAULT; + m41t11m6_settime(&rtime); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/*****************************************************************************/ + +/* + * Exported file operations structure for driver... + */ +static struct file_operations m41t11m6_fops = +{ + .owner = THIS_MODULE, + .read = m41t11m6_read, + .write = m41t11m6_write, + .ioctl = m41t11m6_ioctl, +}; + +static struct miscdevice m41t11m6_dev = +{ + RTC_MINOR, + "rtc", + &m41t11m6_fops +}; + +/*****************************************************************************/ + +static int __init m41t11m6_init(void) +{ + m41t11m6_setup(); + misc_register(&m41t11m6_dev); + printk ("M41T11M6: Real Time Clock driver\n"); + return 0; +} + +static void __exit m41t11m6_exit(void) +{ + misc_deregister(&m41t11m6_dev); +} + +/*****************************************************************************/ + +module_init(m41t11m6_init); +module_exit(m41t11m6_exit); + +MODULE_AUTHOR("Greg Ungerer "); +MODULE_LICENSE("GPL"); + +/*****************************************************************************/ diff --git a/drivers/char/mcf_qspi.c b/drivers/char/mcf_qspi.c new file mode 100644 index 00000000..52e159ee --- /dev/null +++ b/drivers/char/mcf_qspi.c @@ -0,0 +1,857 @@ +/************************************************************************/ +/* */ +/* mcf_qspi.c - QSPI driver for MCF5272, MCF5235, MCF5282 */ +/* */ +/* (C) Copyright 2001, Wayne Roberts (wroberts1@home.com) */ +/* */ +/* Driver has an 8bit mode, and a 16bit mode. */ +/* Transfer size QMR[BITS] is set thru QSPIIOCS_BITS. */ +/* When size is 8, driver works normally: */ +/* a char is sent for every transfer */ +/* When size is 9 to 16bits, driver reads & writes the QDRs with */ +/* the buffer cast to unsigned shorts. The QTR & QRR registers can */ +/* be filled with up to 16bits. The length passed to read/write must */ +/* be of the number of chars (2x number of shorts). This has been */ +/* tested with 10bit a/d and d/a converters. */ +/* */ +/* * QSPIIOCS_READDATA: */ +/* data to send out during read */ +/* * all other ioctls are global */ +/* -------------------------------------------------------------------- */ +/* Ported to linux-2.4.x by Ron Fial (ron@fial.com) August 26,2002 */ +/* */ +/* Added new include files */ +/* Added module_init(),exit(), */ +/* qspi_read(),qspi_write(): Revised qspi_read & write argument */ +/* processing to handle new *filep argument. Changed i_rdev access */ +/* to use filep->f_dentry->d_inode->i_rdev Changed memcpy_fromfs() */ +/* to memcpy(). */ +/* Added '__init' to compiled-in init routine for memory recovery */ +/* Added '__exit' for loadable-driver module cleanup routine */ +/* changed register_chrdev to devfs_register_chrdev */ +/* changed unregister_chrdev to devfs_unregister_chrdev */ +/* Changed various declarations from int to ssize_t or loff_t */ +/* -------------------------------------------------------------------- */ +/* Changed interruptible_sleep_on to sleep_on so the driver has */ +/* chance to finish the current transfer before application */ +/* quits when typing '^C'. Otherwise a write collision will */ +/* most likely occur. */ +/* Added safe_flags(); cli; and frestore_flags() according to */ +/* gerg@snapgear.com. Otherwise in some cases (higher clock */ +/* rates) the transfer is finished before the current process */ +/* is put to sleep and therefore never wakes up again. */ +/* 09/12/2002 richard@opentcp.org */ +/* -------------------------------------------------------------------- */ +/* 02/06/2003 josef.baumgartner@telex.de */ +/* */ +/* Renamed cleanup_module() to qspi_exit() to be able to */ +/* compile as module. */ +/* Removed init_module() because module_init(qspi_init) does all */ +/* we need. */ +/* Changed */ +/* SPI register settings will be saved for each instance to be able */ +/* to use different communication settings for different tasks. */ +/* An ioctl() does not longer write directly to the SPI registers. */ +/* It saves the settings which will be copied into the SPI */ +/* registers on every read()/write(). */ +/* Added MODULE_LICENSE("GPL") to avoid tainted kernel message. */ +/* I think it is GPL?? There's no comment about this?? */ +/* Added polling mode */ +/* Increases performance for small data transfers. */ +/* Added odd mode */ +/* If an odd number of bytes is transfered and 16bit transfers are */ +/* used, the last byte is transfered in byte mode. */ +/* Added dsp mode */ +/* If dsp mode is set, transfers will be limited to 15 bytes */ +/* instead of 16. This ensures that DSPs with 24bit words get */ +/* whole words within one transfer. */ +/* -------------------------------------------------------------------- */ +/* 16/09/2003 ivan.zanin@bluewin.ch */ +/* */ +/* Changed init and exit code to support the MCF5249 */ +/* -------------------------------------------------------------------- */ +/* Oct 19, 2004 jsujjavanich@syntech-fuelmaster.com */ +/* */ +/* Adjusted minor number detection to work with one dev per QSPI_CS */ +/* -------------------------------------------------------------------- */ +/* 17/11/2004 chris_jones_oz@yahoo.com.au */ +/* */ +/* Changed init and exit code to support the MCF5282 */ +/* -------------------------------------------------------------------- */ +/* 050712 jherrero@hvsistemas.es */ +/* */ +/* Ported to kernel 2.6.x, tested only write on MCF5272 */ +/* -------------------------------------------------------------------- */ +/************************************************************************/ + +/* ********************************************************************** +Chapter 14. (excerpt) Queued Serial Peripheral Interface (QSPI) Module + From: http://e-www.motorola.com/brdata/PDFDB/docs/MCF5272UM.pdf + +The following steps are necessary to set up the QSPI 12-bit data transfers +and a QSPI_CLK of 4.125 MHz. The QSPI RAM is set up for a queue of 16 +transfers. All four QSPI_CS signals are used in this example. + +1. Enable all QSPI_CS pins on the MCF5272. Write PACNT with 0x0080_4000 to +enable QSPI_CS1 and QSPI_CS3.Write PDCNT with 0x0000_0030 to enable QSPI_CS2. + +2. Write the QMR with 0xB308 to set up 12-bit data words with the data +shifted on the falling clock edge, and a clock frequency of 4.125 MHz +(assuming a 66-MHz CLKIN). + +3. Write QDLYR with the desired delays. + +4. Write QIR with 0xD00F to enable write collision, abort bus errors, and +clear any interrupts. + +5. Write QAR with 0x0020 to select the first command RAM entry. + +6. Write QDR with 0x7E00, 0x7E00, 0x7E00, 0x7E00, 0x7D00, 0x7D00, 0x7D00, +0x7D00, 0x7B00, 0x7B00, 0x7B00, 0x7B00, 0x7700, 0x7700, 0x7700, and 0x7700 +to set up four transfers for each chip select. The chip selects are active +low in this example. NOTE: QDR value auto-increments after each write. + +7. Write QAR with 0x0000 to select the first transmit RAM entry. + +8. Write QDR with sixteen 12-bit words of data. + +9. Write QWR with 0x0F00 to set up a queue beginning at entry 0 and ending +at entry 15. + +10. Set QDLYR[SPE] to enable the transfers. + +11.Wait until the transfers are complete. QIR[SPIF] is set when the +transfers are complete. + +12. Write QAR with 0x0010 to select the first receive RAM entry. + +13. Read QDR to get the received data for each transfer. NOTE: QDR +auto-increments. + +14. Repeat steps 5 through 13 to do another transfer. + +************************************************************************* */ +#include /* gets us MCF_MBAR value */ +#include /* MCFSIM offsets */ +#include +#include /* cli() and friends */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Include versioning info, if needed */ +#if (defined(MODULE) && defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)) +#define MODVERSIONS +#endif + +#if defined(MODVERSIONS) +#include +#endif + +#include "mcf_qspi.h" + + +#define DEVICE_NAME "qspi" + +int __init qspi_init(void); +static int init(void); +void __exit qspi_exit(void); + + +/* struct wait_queue *wqueue; */ +static DECLARE_WAIT_QUEUE_HEAD(wqueue); /* use ver 2.4 static declaration - ron */ +/* or should we use wait_queue_heat_t *wqueue ?? see page 141 */ + +static unsigned char dbuf[1024]; + +/* static struct semaphore sem = MUTEX; */ + + +#if LINUX_VERSION_CODE < 0x020100 +static struct semaphore sem = MUTEX; +#else +static DECLARE_MUTEX(sem); +#endif + + +irqreturn_t qspi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u16 qir = (QIR & (QIR_WCEF | QIR_ABRT | QIR_SPIF)); + + /* Check write collision and transfer abort flags. Report any + * goofiness. */ + if (qir & QIR_WCEF) + printk(KERN_INFO "%s: WCEF\n", __FILE__); + + if (qir & QIR_ABRT) + printk(KERN_INFO "%s: ABRT\n", __FILE__); + + /* Check for completed transfer. Wake any tasks sleeping on our + * global wait queue. */ + if (qir & QIR_SPIF) + wake_up(&wqueue); + + /* Clear any set flags. */ + QIR |= qir; + return IRQ_HANDLED; +} + + +static int qspi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct qspi_dev *dev = filp->private_data; + struct qspi_read_data *read_data; + int error; + + down(&sem); + + switch (cmd) { + /* Set QMR[DOHIE] (high-z Dout between transfers) */ + case QSPIIOCS_DOUT_HIZ: + dev->dohie = (arg ? 1 : 0); + break; + + /* Set QMR[BITS] */ + case QSPIIOCS_BITS: + if (((arg > 0) && (arg < 8)) || (arg > 16)) { + ret = -EINVAL; + break; + } + + dev->bits = (u8)arg; + break; + + /* Get QMR[BITS] */ + case QSPIIOCG_BITS: + *((int *)arg) = dev->bits; + break; + + /* Set QMR[CPOL] (QSPI_CLK inactive state) */ + case QSPIIOCS_CPOL: + dev->cpol = (arg ? 1 : 0); + break; + + /* Set QMR[CPHA] (QSPI_CLK phase, 1 = rising edge) */ + case QSPIIOCS_CPHA: + dev->cpha = (arg ? 1 : 0); + break; + + /* Set QMR[BAUD] (QSPI_CLK baud rate divisor) */ + case QSPIIOCS_BAUD: + if (arg > 255) { + ret = -EINVAL; + break; + } + + dev->baud = (u8)arg; + break; + + /* Set QDR[QCD] (QSPI_CS to QSPI_CLK setup) */ + case QSPIIOCS_QCD: + if (arg > 127) { + ret = -EINVAL; + break; + } + + dev->qcd = (u8)arg; + break; + + /* Set QDR[DTL] (QSPI_CLK to QSPI_CS hold) */ + case QSPIIOCS_DTL: + if (arg > 255) { + ret = -EINVAL; + break; + } + + dev->dtl = (u8)arg; + break; + + /* Set QCRn[CONT] (QSPI_CS continuous mode, 1 = remain + * asserted after transfer of 16 data words) */ + case QSPIIOCS_CONT: + dev->qcr_cont = (arg ? 1 : 0); + break; + + /* Set DSP mode, used to limit transfers to 15 bytes for + * 24-bit DSPs */ + case QSPIIOCS_DSP_MOD: + dev->dsp_mod = (arg ? 1 : 0); + break; + + /* If an odd count of bytes is transferred, force the transfer + * of the last byte to byte mode, even if word mode is used */ + case QSPIIOCS_ODD_MOD: + dev->odd_mod = (arg ? 1 : 0); + break; + + /* Set data buffer to be used as "send data" during reads */ + case QSPIIOCS_READDATA: + read_data = (struct qspi_read_data *)arg; + error = !access_ok(VERIFY_READ, read_data, + sizeof(struct qspi_read_data)); + if (error) { + ret = -EFAULT; + break; + } + + if (read_data->length > sizeof(read_data->buf)) { + // possible bug here when want length > 4 + ret = -EINVAL; + break; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + memcpy_fromfs(&dev->read_data, read_data, + sizeof(struct qspi_read_data)); +#else + copy_from_user(&dev->read_data, read_data, + sizeof(struct qspi_read_data)); +#endif + break; + + /* Set driver to use polling mode, which may increase + * performance for small transfers */ + case QSPIIOCS_POLL_MOD: + dev->poll_mod = (arg ? 1 : 0); + break; + + default: + ret = -EINVAL; + break; + } + + up(&sem); + return(ret); +} + + +static int qspi_open(struct inode *inode, struct file *file) +{ + qspi_dev *dev; + +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_INC_USE_COUNT; + #endif */ + + if ((dev = kmalloc(sizeof(qspi_dev), GFP_KERNEL)) == NULL) { + /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_DEC_USE_COUNT; + #endif */ + return(-ENOMEM); + } + + /* set default values */ + dev->read_data.length = 0; + dev->read_data.buf = 0; + dev->read_data.loop = 0; + dev->poll_mod = 0; /* interrupt mode */ + dev->bits = 8; + dev->cpol = 0; + dev->cpha = 0; + dev->qcr_cont = 1; + dev->dsp_mod = 0; /* no DSP mode */ + dev->odd_mod = 0; /* no ODD mode */ + dev->qcd = 17; + dev->dtl = 1; + + file->private_data = dev; + + return(0); +} + + +static int qspi_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_DEC_USE_COUNT; + #endif */ + + return(0); +} + + +// basic 2.4 kernel function format +// ssize_t qspi_read(struct file* w12f, char * w12c, size_t w12d, loff_t * w12e) { ; } + + +static ssize_t qspi_read(struct file *filep, char *buffer, size_t length, + loff_t *off) +/******** older 2.0 kernel format ********** +static int qspi_read( + struct inode *inode, + struct file *filep, + char *buffer, + int length) +********************************************/ +{ + int qcr_cs; + int total = 0; + int i = 0; + int max_trans; + unsigned char bits; + unsigned char word = 0; + unsigned long flag; + qspi_dev *dev; + int rdi = 0; + + down(&sem); + + dev = filep->private_data; + + /* set the register with default values */ + QMR = QMR_MSTR | + (dev->dohie << 14) | + (dev->bits << 10) | + (dev->cpol << 9) | + (dev->cpha << 8) | + (dev->baud); + + QDLYR = (dev->qcd << 8) | dev->dtl; + + if (dev->dsp_mod) + max_trans = 15; + else + max_trans = 16; + + //qcr_cs = (~MINOR(filep->f_dentry->d_inode->i_rdev) << 8) & 0xf00; /* CS for QCR */ + qcr_cs = 0xf00 & ~(1 << (8 + MINOR(filep->f_dentry->d_inode->i_rdev))); + + bits = dev->bits % 0x10; + if (bits == 0 || bits > 0x08) + word = 1; /* 9 to 16bit transfers */ + +// printk("\n READ driver -- ioctl xmit data fm dev->read_data.buf array %x %x %x %x \n",dev->read_data.buf[0],dev->read_data.buf[1],dev->read_data.buf[2],dev->read_data.buf[3]); + + while (i < length) { + unsigned short *sp = (unsigned short *)&buffer[i]; + unsigned char *cp = &buffer[i]; + unsigned short *rd_sp = (unsigned short *)dev->read_data.buf; + int x; + int n; + + QAR = TX_RAM_START; /* address first QTR */ + for (n = 0; n < max_trans; n++) { + if (rdi != -1) { + if (word) { + if (rd_sp) + QDR = rd_sp[rdi++]; + else + QDR = 0; + if (rdi == dev->read_data.length >> 1) + rdi = dev->read_data.loop ? 0 : -1; + } else { + if (dev->read_data.buf) + QDR = dev->read_data.buf[rdi++]; + else + QDR = 0; + if (rdi == dev->read_data.length) + rdi = dev->read_data.loop ? 0 : -1; + } + } else + QDR = 0; + + i++; + if (word) + i++; + if (i > length) + break; + } + + QAR = COMMAND_RAM_START; /* address first QCR */ + for (x = 0; x < n; x++) { + /* QCR write */ + if (dev->qcr_cont) { + if (x == n - 1 && i == length) + QDR = QCR_SETUP | qcr_cs; /* last transfer */ + else + QDR = QCR_CONT | QCR_SETUP | qcr_cs; + } else + QDR = QCR_SETUP | qcr_cs; + } + + QWR = QWR_CSIV | ((n - 1) << 8); + + /* check if we are using polling mode. Polling increases + * performance for samll data transfers but is dangerous + * if we stay too long here, locking other tasks!! + */ + if (dev->poll_mod) { + QIR = QIR_SETUP_POLL; + QDLYR |= QDLYR_SPE; + + while ((QIR & QIR_SPIF) != QIR_SPIF) + ; + QIR = QIR | QIR_SPIF; + } else { + QIR = QIR_SETUP; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + save_flags(flag); cli(); // like in write function +#else + local_irq_save(flag); +#endif + + QDLYR |= QDLYR_SPE; +// interruptible_sleep_on(&wqueue); + sleep_on(&wqueue); // changed richard@opentcp.org +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + restore_flags(flag); // like in write function +#else + local_irq_restore(flag); +#endif + } + + QAR = RX_RAM_START; /* address: first QRR */ + if (word) { + /* 9 to 16bit transfers */ + for (x = 0; x < n; x++) { + put_user(*(volatile unsigned short *)(MCF_MBAR + MCFSIM_QDR), sp++); + } + } else { + /* 8bit transfers */ + for (x = 0; x < n; x++) + put_user(*(volatile unsigned short *)(MCF_MBAR + MCFSIM_QDR), cp++); + } + + if (word) + n <<= 1; + + total += n; + } + + up(&sem); + return(total); +} + + + +static ssize_t qspi_write(struct file *filep, const char *buffer, size_t length, + loff_t *off) +{ + int qcr_cs; + int i = 0; + int total = 0; + int z; + int max_trans; + unsigned char bits; + unsigned char word = 0; + unsigned long flag; + qspi_dev *dev; + + down(&sem); + + dev = filep->private_data; + + QMR = QMR_MSTR | + (dev->dohie << 14) | + (dev->bits << 10) | + (dev->cpol << 9) | + (dev->cpha << 8) | + (dev->baud); + + QDLYR = (dev->qcd << 8) | dev->dtl; + + bits = (QMR >> 10) % 0x10; + if (bits == 0 || bits > 0x08) + word = 1; /* 9 to 16 bit transfers */ + + //qcr_cs = (~MINOR(filep->f_dentry->d_inode->i_rdev) << 8) & 0xf00; /* CS for QCR */ + qcr_cs = 0xf00 & ~(1 << (8 + MINOR(filep->f_dentry->d_inode->i_rdev))); + + /* next line was memcpy_fromfs() */ + copy_from_user (dbuf, buffer, length); + +// printk("data to write is %x %x %x %X \n",dbuf[0],dbuf[1],dbuf[2],dbuf[3]); + + if (dev->odd_mod) + z = QCR_SETUP8; + else + z = QCR_SETUP; + + if (dev->dsp_mod) + max_trans = 15; + else + max_trans = 16; + + while (i < length) { + int x; + int n; + + QAR = TX_RAM_START; /* address: first QTR */ + if (word) { + for (n = 0; n < max_trans; ) { + /* in odd mode last byte will be transfered in byte mode */ + if (dev->odd_mod && (i + 1 == length)) { + QDR = dbuf[i]; /* tx data: QDR write */ + // printk("0x%X ", dbuf[i]); + n++; + i++; + break; + } + else { + QDR = (dbuf[i] << 8) + dbuf[i+1]; /* tx data: QDR write */ + //printk("0x%X 0x%X ", dbuf[i], dbuf[i+1]); + n++; + i += 2; + if (i >= length) + break; + } + } + } else { + /* 8bit transfers */ + for (n = 0; n < max_trans; ) { + QDR = dbuf[i]; /* tx data: QTR write */ + n++; + i++; + if (i == length) + break; + } + } + + QAR = COMMAND_RAM_START; /* address: first QCR */ + for (x = 0; x < n; x++) { + /* QCR write */ + if (dev->qcr_cont) { + if (x == n-1 && i == length) + if ((i % 2)!= 0) + QDR = z | qcr_cs; /* last transfer and odd number of chars */ + else + QDR = QCR_SETUP | qcr_cs; /* last transfer */ + else + QDR = QCR_CONT | QCR_SETUP | qcr_cs; + } else { + if (x == n - 1 && i == length) + QDR = z | qcr_cs; /* last transfer */ + else + QDR = QCR_SETUP | qcr_cs; + } + } + + QWR = QWR_CSIV | ((n - 1) << 8); /* QWR[ENDQP] = n << 8 */ + + /* check if we are using polling mode. Polling increases + * performance for samll data transfers but is dangerous + * if we stay too long here, locking other tasks!! + */ + if (dev->poll_mod) { + QIR = QIR_SETUP_POLL; + QDLYR |= QDLYR_SPE; + + while ((QIR & QIR_SPIF) != QIR_SPIF) + ; + QIR = QIR | QIR_SPIF; + } else { + QIR = QIR_SETUP; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + save_flags(flag); cli(); // added according to gerg@snapgear.com +#else + local_irq_save(flag); +#endif + QDLYR |= QDLYR_SPE; + +// interruptible_sleep_on(&wqueue); + sleep_on(&wqueue); // changed richard@opentcp.org + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + restore_flags(flag); // added according to gerg@snapgear.com +#else + local_irq_restore(flag); +#endif + } + + + if (word) + n <<= 1; + + total += n; + } + + up(&sem); + return(total); +} + + +/* fixed for 2.4 kernel, owner was ifdef'ed out for 2.0 kernel */ +static struct file_operations Fops = { + owner: THIS_MODULE, + read: qspi_read, + write: qspi_write, + ioctl: qspi_ioctl, + open: qspi_open, + release: qspi_release /* a.k.a. close */ +}; + + +static int init(void) +{ + volatile u32 *lp; + volatile u8 *cp; + + /* common init: driver or module: */ + + if (request_irq(MCFQSPI_IRQ_VECTOR, qspi_interrupt, SA_INTERRUPT, "ColdFire QSPI", NULL)) { + printk("QSPI: Unable to attach ColdFire QSPI interrupt " + "vector=%d\n", MCFQSPI_IRQ_VECTOR); + return(-EINVAL); + } + +#if defined(CONFIG_M5249) + cp = (volatile u8 *)(MCF_MBAR + MCFSIM_ICR10); + *cp = 0x8f; /* autovector on, il=3, ip=3 */ + + lp = (volatile u32 *)(MCF_MBAR2 + 0x180); + *lp |= 0x00000800; /* activate qspi_in and qspi_clk */ + + lp = (volatile u32 *)(MCF_MBAR2 + MCFSIM2_GPIOFUNC); + *lp &= 0xdc9FFFFF; /* activate qspi_cs0 .. 3, qspi_dout */ + + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_IMR); + *lp &= 0xFFFbFFFF; /* enable qspi interrupt */ +#elif defined(CONFIG_M523x) + // interrupts mask here + cp = (volatile unsigned char *)(MCF_MBAR + MCF5235ICM_INTC0 + MCFINTC0_ICR); + cp[IRQ_SOURCE] = (( 3/*IL*/ & 0x3 ) << 3 ) | (3 /*IP*/ & 0x3); + + lp = (volatile u32 *)(MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + *lp &= ~((1 << MCFINT_QSPI) | 1); // cannot set bit 0 + // GPIO here + { + volatile unsigned char *parp; + parp = (volatile unsigned char *)(MCF_MBAR + 0x10004A); + *parp = 0xFF; + } +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)) + cp = (volatile u8 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + + MCFINT_QSPI); + *cp = (5 << 3) + 3; /* level 5, priority 3 */ + + cp = (volatile u8 *) (MCF_IPSBAR + MCF5282_GPIO_PQSPAR); + *cp = 0x7f; /* activate din, dout, clk and cs[0..3] */ + + lp = (volatile u32 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL); + *lp &= ~(1 + (1 << MCFINT_QSPI)); /* enable qspi interrupt */ +#else + /* set our IPL */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_ICR4); + *lp = (*lp & 0x07777777) | 0xd0000000; + + /* 1) CS pin setup 17.2.x + * Dout, clk, cs0 always enabled. Din, cs[3:1] must be enabled. + * CS1: PACNT[23:22] = 10 + * CS1: PBCNT[23:22] = 10 ? + * CS2: PDCNT[05:04] = 11 + * CS3: PACNT[15:14] = 01 + */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_PACNT); + *lp = (*lp & 0xFF3F3FFF) | 0x00804000; /* 17.2.1 QSPI CS1 & CS3 */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_PDCNT); + *lp = (*lp & 0xFFFFFFCF) | 0x00000030; /* QSPI_CS2 */ +#endif + + /* + * These values have to be setup according to the applications + * using the qspi driver. Maybe some #defines at the beginning + * would be more appropriate. Especially the transfer size + * and speed settings + */ + QMR = 0xA1A2; // default mode setup: 8 bits, baud, 160kHz clk. +// QMR = 0x81A2; // default mode setup: 16 bits, baud, 160kHz clk. + QDLYR = 0x0202; // default start & end delays + + init_waitqueue_head(&wqueue); /* was init_waitqueue() --Ron */ + +#if defined(CONFIG_M5249) + printk("MCF5249 QSPI driver ok\n"); +#elif defined(CONFIG_M523x) + printk("MCF5235 QSPI driver ok\n"); +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)) + printk("MCF5282 QSPI driver ok\n"); +#else + printk("MCF5272 QSPI driver ok\n"); +#endif + + return(0); +} + +/* init for compiled-in driver: call from mem.c */ +int __init qspi_init(void) /* the __init added by ron */ +{ + int ret; + + if ((ret = register_chrdev(QSPI_MAJOR, DEVICE_NAME, &Fops) < 0)) { + + printk ("%s device failed with %d\n", + "Sorry, registering the character", ret); + return(ret); + } + + printk ("QSPI device driver installed OK\n"); + return(init()); +} + +/* Cleanup - undid whatever init_module did */ +void __exit qspi_exit(void) /* the __exit added by ron */ +{ + int ret; + + free_irq(MCFQSPI_IRQ_VECTOR, NULL); + +#if defined(CONFIG_M5249) + /* autovector on, il=0, ip=0 */ + *(volatile u8 *)(MCF_MBAR + MCFSIM_ICR10) = 0x80; + /* disable qspi interrupt */ + *(volatile u32 *)(MCF_MBAR + MCFSIM_IMR) |= 0x00040000; +#elif defined(CONFIG_M523x) + { + volatile unsigned char *icrp; + icrp = (volatile unsigned char *)(MCF_MBAR + MCF5235ICM_INTC0 + MCFINTC0_ICR); + icrp[IRQ_SOURCE] = 0; + } + { + volatile unsigned long *imrl; + imrl = (volatile unsigned long *)(MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + *imrl |= (1 << MCFINT_QSPI); + } + // GPIO here + { + volatile unsigned char *parp; + parp = (volatile unsigned char *)(MCF_MBAR + 0x10004A); + *parp = 0x00; + } +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)) + /* interrupt level 0, priority 0 */ + *(volatile u8 *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_QSPI) = 0; + /* disable qspi interrupt */ + *(volatile u32 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL) + |= (1 << MCFINT_QSPI); +#else + /* zero our IPL */ + *((volatile u32 *)(MCF_MBAR + MCFSIM_ICR4)) = 0x80000000; +#endif + + /* Unregister the device */ + if ((ret = unregister_chrdev(QSPI_MAJOR, DEVICE_NAME)) < 0) + + printk("Error in unregister_chrdev: %d\n", ret); +} + + +module_init(qspi_init); /* added by ron so driver can compile directly into kernel */ +module_exit(qspi_exit); /* added by ron so driver can compile directly into kernel */ + +MODULE_LICENSE("GPL"); + diff --git a/drivers/char/mcf_qspi.h b/drivers/char/mcf_qspi.h new file mode 100644 index 00000000..09fca07d --- /dev/null +++ b/drivers/char/mcf_qspi.h @@ -0,0 +1,94 @@ +#if !defined(MCF_QSPI_H) +#define MCF_QSPI_H + +#include +#include + + +#define QSPI_MAJOR 126 +#if defined(CONFIG_M5249) +#define MCFQSPI_IRQ_VECTOR 27 +#define QSPIMOD_OFFSET 0x400 +#elif defined(CONFIG_M523x) +#define MCF5235ICM_INTC0 0xC00 +#define MCFINTC0_ICR 0x40 +#define MCFQSPI_IRQ_VECTOR 82 +#define QSPIMOD_OFFSET 0x340 +#define IRQ_SOURCE 18 +#define MCF5235INTC_IMRL 0x0C +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)) +#define MCFQSPI_IRQ_VECTOR (64 + 18) +#define QSPIMOD_OFFSET 0x340 +#else +#define MCFQSPI_IRQ_VECTOR 89 +#define QSPIMOD_OFFSET 0xa0 +#endif + + +/* QSPI registers */ +#define MCFSIM_QMR (0x00 + QSPIMOD_OFFSET) /* mode */ +#define MCFSIM_QDLYR (0x04 + QSPIMOD_OFFSET) /* delay */ +#define MCFSIM_QWR (0x08 + QSPIMOD_OFFSET) /* wrap */ +#define MCFSIM_QIR (0x0c + QSPIMOD_OFFSET) /* interrupt */ +#define MCFSIM_QAR (0x10 + QSPIMOD_OFFSET) /* address */ +#define MCFSIM_QDR (0x14 + QSPIMOD_OFFSET) /* address */ + +#define TX_RAM_START 0x00 +#define RX_RAM_START 0x10 +#define COMMAND_RAM_START 0x20 + +#define QMR *(volatile u16 *)(MCF_MBAR + MCFSIM_QMR) +#define QAR *(volatile u16 *)(MCF_MBAR + MCFSIM_QAR) +#define QDR *(volatile u16 *)(MCF_MBAR + MCFSIM_QDR) +#define QWR *(volatile u16 *)(MCF_MBAR + MCFSIM_QWR) +#define QDLYR *(volatile u16 *)(MCF_MBAR + MCFSIM_QDLYR) +#define QIR *(volatile u16 *)(MCF_MBAR + MCFSIM_QIR) + + +/* bits */ +#define QMR_MSTR 0x8000 /* master mode enable: must always be set */ +#define QMR_DOHIE 0x4000 /* shut off (hi-z) Dout between transfers */ +#define QMR_BITS 0x3c00 /* bits per transfer (size) */ +#define QMR_CPOL 0x0200 /* clock state when inactive */ +#define QMR_CPHA 0x0100 /* clock phase: 1 = data taken at rising edge */ +#define QMR_BAUD 0x00ff /* clock rate divider */ + +#define QIR_WCEF 0x0008 /* write collison */ +#define QIR_ABRT 0x0004 /* abort */ +#define QIR_SPIF 0x0001 /* finished */ +#define QIR_SETUP 0xdd0f /* setup QIR for tranfer start */ +#define QIR_SETUP_POLL 0xdc0d /* setup QIR for tranfer start */ + +#define QWR_CSIV 0x1000 /* 1 = active low chip selects */ + +#define QDLYR_SPE 0x8000 /* initiates transfer when set */ +#define QDLYR_QCD 0x7f00 /* start delay between CS and first clock */ +#define QDLYR_DTL 0x00ff /* delay after CS release */ + +/* QCR: chip selects return to inactive, bits set in QMR[BITS], + * after delay set in QDLYR[DTL], pre-delay set in QDLYR[QCD] */ +#define QCR_SETUP 0x7000 +#define QCR_CONT 0x8000 /* 1=continuous CS after transfer */ +#define QCR_SETUP8 0x3000 /* sets BITSE to 0 => eigth bits per transfer */ + + +typedef struct qspi_dev { + qspi_read_data read_data; + u8 bits; /* transfer size, number of bits to transfer for each entry */ + u8 baud; /* baud rate */ + u8 qcd; /* QSPILCK delay */ + u8 dtl; /* delay after transfer */ + unsigned int qcr_cont : 1; /* keep CS active throughout transfer */ + unsigned int odd_mod : 1; /* if length of buffer is a odd number, 16-bit transfers + are finalized with a 8-bit transfer */ + unsigned int dsp_mod : 1; /* transfers are bounded to 15/30 bytes + (= a multiple of 3 bytes = 1 word) */ + unsigned int poll_mod : 1; /* mode polling or interrupt */ + unsigned int cpol : 1; /* SPI clock polarity */ + unsigned int cpha : 1; /* SPI clock phase */ + unsigned int dohie : 1; /* data output high impedance enable */ +} qspi_dev; + + +#endif /* MCF_QSPI_H */ + diff --git a/drivers/char/mcfwatchdog.c b/drivers/char/mcfwatchdog.c new file mode 100644 index 00000000..15ce431b --- /dev/null +++ b/drivers/char/mcfwatchdog.c @@ -0,0 +1,365 @@ +/***************************************************************************/ + +/* + * linux/drivers/char/mcfwatchdog.c + * + * Copyright (C) 1999-2000, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * Changes: + * 10/28/2004 Christian Magnusson + * Bug: MCFSIM_SYPCR can only be written once after reset! + * MCF5272 support copied from 2.4.x driver. + * Reset on overflow. (For 5206e at least) + * Added module support. + * I have noticed that some flash-identification from mtd + * locks the processor too long, and therefor this watchdog + * has to be used as a module and started after mtd is done. + * + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +/* + * Define the watchdog vector. + */ +#ifdef CONFIG_M5272 +#define IRQ_WATCHDOG 92 +#define TIMEPOLL 100 +#else +#define IRQ_WATCHDOG 250 +#define TIMEPOLL HZ/100 +#endif + +#if defined(CONFIG_M5206e) +#define RESET_ON_SWTR +#endif + +/***************************************************************************/ + +void watchdog_alive(unsigned long arg); +static irqreturn_t watchdog_timeout(int irq, void *dummy, struct pt_regs *fp); + +#ifndef MODULE +extern void dump(struct pt_regs *fp); +#endif + +/* + * Data for registering the watchdog alive routine with ticker. + */ +static struct timer_list watchdog_timerlist; + +static int watchdog_overflows; + +#ifdef CONFIG_OLDMASK +/* + * The old mask 5307 has a broken watchdog timer. It will interrupt + * you regardless of writing to its "alive" register. It can still + * be useful but you have to play some tricks with it. This code + * supports a clock ticker timeout. If the right number of clock + * ticks are not counted then it is assumed that the watchdog saved + * us from a bad bus cycle. + */ +#define SWTREF_COUNT 25 + +int swt_inwatchdog = 0; /* Has watchdog expired */ +int swt_doit = 0; /* Start delay before tripping */ +int swt_lastjiffies = 0; /* Tick count at last watchdog */ +int swt_reference = SWTREF_COUNT; /* Refereence tick count */ +#endif + + +static struct file_operations watchdog_fops = { + .owner = THIS_MODULE, +}; + +static struct miscdevice watchdog_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &watchdog_fops, +}; + +/***************************************************************************/ + +/* + * Software Watchdog Timer enable. Seems to be the same across all + * ColdFire CPU members. + */ +void watchdog_enable(void) +{ +#ifdef CONFIG_M5272 + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WRRR) = 0x2001; // upper watchdog limit + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WIRR) = 0x1000; // we don't do interrupts, just reset (o; + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000; // clear counter +#else /* CONFIG_M5272 */ + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + *(mbar + MCFSIM_SWSR) = 0x55; + *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog + + /* + SYPCR Can only be written once after system reset! + 0x80 Software Watchdog, 0="Disable" / 1="Enable" + 0x40 Software Watchdog, 0="level7 interrupt" / 1="reset" + 0x20 Watchdog prescaled (SWP), 0="1" / 1="512" + 0x10 Timing SWT1 + 0x08 Timing SWT0 + SWT|SWT1|SWT0 + 000=2^9 001=2^11 010=2^13 011=2^15 / System Freq. + 100=2^18 101=2^20 110=2^22 111=2^24 / System Freq. + 0x04 Bus Timeout Monitor BMTE 0="Disable" / 1="Enable" + 0x02 Bus Monitor Timing BMT1 + 0x01 Bus Monitor Timing BMT0 + BMT1|BMT0 + 00=1024 01=512 10=256 11=128 system clocks + */ +#ifdef CONFIG_OLDMASK + *(mbar + MCFSIM_SYPCR) = 0xbe; // level 7 interrupt, 2^22 +#else + +#ifdef RESET_ON_SWTR + *(mbar + MCFSIM_SYPCR) = 0xfe; // reset, 2^22 +#else + *(mbar + MCFSIM_SYPCR) = 0xbe; // level 7 interrupt, 2^22 +#endif /* RESET_ON_SWTR */ +#endif /* CONFIG_OLDMASK */ +#endif /* CONFIG_M5272 */ +} + +/***************************************************************************/ + +void watchdog_disable(void) +{ +#ifdef CONFIG_M5272 + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WRRR) = 0xFFFE; + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WIRR) = 0x0000; + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000; +#else + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + /* + If watchdog is set to 'reset', this function is useless... + If timer is disabled, this reset will occour at once. + */ + *(mbar + MCFSIM_SWSR) = 0x55; + *(mbar + MCFSIM_SWSR) = 0xaa; +#if 0 + /* + SYPCR Can only be written once after system reset! + This will probably be ignored according to MCF5206E User Manual + */ + *(mbar + MCFSIM_SYPCR) = 0x00 /*0x3e*/; +#endif + mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD); +#endif + del_timer(&watchdog_timerlist); +} + +/***************************************************************************/ + +static int watchdog_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) { + /* Turn the card off */ + watchdog_disable(); + /* + If watchdog is set to 'reset', this function is useless... + When timer is disabled, reset will occour during reboot... + */ + } + return NOTIFY_DONE; +} + +static struct notifier_block watchdog_notifier = { + .notifier_call = watchdog_notify_sys, +}; + +/***************************************************************************/ + +/* + * Process a watchdog timeout interrupt. For a normal clean watchdog + * we just do a process dump. For old broken 5307 we need to verify + * if this was a real watchdog event or not... + */ +static irqreturn_t watchdog_timeout(int irq, void *dummy, struct pt_regs *fp) +{ +#ifdef CONFIG_OLDMASK +#define TIMEDELAY 45 + /* + * Debuging code for software watchdog. If we get in here + * and timer interrupt counts don't match we know that a + * bad external bus cycle must have locked the CPU. + */ + if ((swt_doit++ > TIMEDELAY) && + ((swt_lastjiffies + swt_reference) > jiffies)) { + if (swt_inwatchdog) { + cli(); + watchdog_disable(); + mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD); + printk("%s(%d): Double WATCHDOG PANIC!!\n", + __FILE__, __LINE__); + for (;;) + ; + } + + swt_inwatchdog++; + swt_doit = TIMEDELAY - 8; /* 8 seconds grace */ + printk("mcfwatchdog: expired last=%d(%d) jiffies=%d!\n", + swt_lastjiffies, swt_reference, jiffies); +#ifndef MODULE + dump(fp); +#endif + force_sig(SIGSEGV, current); + swt_inwatchdog = 0; + } + swt_lastjiffies = jiffies; +#else + +#ifdef RESET_ON_SWTR + /* nothing will be done... reset will occour */ +#else /* RESET_ON_SWTR */ + // lev7 interrupt is used. + if(++watchdog_overflows >= 10) { + + printk("mcfwatchdog: expired!\n"); +#ifndef MODULE + dump(fp); +#endif + mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD); + HARD_RESET_NOW(); + for (;;) ; // hang until reboot + } else { + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + *(mbar + MCFSIM_SWSR) = 0x55; + *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog + } +#endif /* RESET_ON_SWTR */ +#endif /* CONFIG_OLDMASK */ + return IRQ_HANDLED; +} + +/***************************************************************************/ + +static int __init watchdog_init(void) +{ + printk("mcfwatchdog: initializing at vector=%d\n", IRQ_WATCHDOG); + + if(misc_register(&watchdog_miscdev)) + return -ENODEV; + + if(register_reboot_notifier(&watchdog_notifier)) { + printk("watchdog: cannot register reboot notifier\n"); + return 1; + } + + request_irq(IRQ_WATCHDOG, watchdog_timeout, SA_INTERRUPT, + "Watchdog Timer", &watchdog_miscdev); + + init_timer (&watchdog_timerlist); + watchdog_timerlist.function = watchdog_alive; + watchdog_timerlist.expires = (jiffies + 1); + add_timer(&watchdog_timerlist); + +#ifdef CONFIG_M5272 +{ + volatile unsigned long *icrp; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR4); + *icrp = (*icrp & 0x77707777) | 0x000E0000; + watchdog_enable(); +} +#else /* CONFIG_M5272 */ +{ + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + unsigned char ch; + + ch = *(mbar + MCFSIM_RSR); + printk("mcfwatchdog: Last reset was generated by %s\n", + (ch&0x80 ? "HRST": (ch&0x20 ? "SWTR":""))); + +#ifdef RESET_ON_SWTR + // high priority just to make sure watchdog won't overflow. + *(mbar + MCFSIM_SWDICR) = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI1; +#else + *(mbar + MCFSIM_SWDICR) = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI3; +#endif + *(mbar + MCFSIM_SWIVR) = IRQ_WATCHDOG; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_SWD); + watchdog_enable(); + + printk("mcfwatchdog: Coldfire watchdog is enabled, \"%s\" is generated on error\n", + ((*(mbar + MCFSIM_SYPCR) & 0x40)? + "Reset" : "Level7 interrupt")); + +#ifdef MODULE + if(*(mbar + MCFSIM_SYPCR) & 0x40) { + printk("mcfwatchdog: Warning: If module is unloaded, Watchdog will reset card.\n"); + } +#endif +} +#endif /* CONFIG_M5272 */ + return 0; +} + +/***************************************************************************/ + +static void __exit watchdog_exit(void) +{ +#ifdef CONFIG_M5272 + /* Reset watchdog counter */ + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000; +#else + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + *(mbar + MCFSIM_RSR) = 0; // clear reset cause +#endif + unregister_reboot_notifier(&watchdog_notifier); + misc_deregister(&watchdog_miscdev); + watchdog_disable(); + printk("mcfwatchdog: Coldfire watchdog is disabled and unloaded\n"); +} + +/***************************************************************************/ + +void watchdog_alive(unsigned long arg) +{ +#ifdef CONFIG_M5272 + /* Reset watchdog counter */ + *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000; +#else + volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR; + *(mbar + MCFSIM_SWSR) = 0x55; + *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog +#endif + /* Re-arm the watchdog alive poll */ + mod_timer(&watchdog_timerlist, jiffies+TIMEPOLL); + watchdog_overflows = 0; +} + +/***************************************************************************/ + +module_init(watchdog_init); +module_exit(watchdog_exit); + +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Coldfire Watchdog Driver"); +MODULE_LICENSE("GPL"); + +/***************************************************************************/ diff --git a/drivers/char/moxalcm.h b/drivers/char/moxalcm.h new file mode 100644 index 00000000..9a8d6a04 --- /dev/null +++ b/drivers/char/moxalcm.h @@ -0,0 +1,31 @@ + +/* + * This is a include file to define Moxa supporting LCM moudle global defined. + * + * History: + * Date Author Commnet + * 09-03-2008 Victor Yu. Create it. + */ + +#ifndef __MOXA_LCM_H +#define __MOXA_LCM_H + +// ioctl command define +#define IOCTL_LCM_GOTO_XY 1 +#define IOCTL_LCM_CLS 2 +#define IOCTL_LCM_CLEAN_LINE 3 +#define IOCTL_LCM_GET_XY 4 +#define IOCTL_LCM_BACK_LIGHT_ON 5 +#define IOCTL_LCM_BACK_LIGHT_OFF 6 +#define IOCTL_LCM_PIX_ON 7 +#define IOCTL_LCM_PIX_OFF 8 +#define IOCTL_LCM_AUTO_SCROLL_ON 13 +#define IOCTL_LCM_AUTO_SCROLL_OFF 14 +#define IOCTL_LCM_SAVE_BYTE 15 +#define IOCTL_LCM_WRITE_BYTE 16 +#define IOCTL_LCM_DISPLAY_OFF 17 +#define IOCTL_LCM_DISPLAY_ON 18 +#define IOCTL_LCM_REVERSE_ON 20 +#define IOCTL_LCM_REVERSE_OFF 21 + +#endif // __MOXA_LCM_H diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c dissimilarity index 80% index 048d9114..3edb0f27 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1,3179 +1,4202 @@ -/* - * mxser.c -- MOXA Smartio/Industio family multiport serial driver. - * - * Copyright (C) 1999-2001 Moxa Technologies (support@moxa.com.tw). - * - * This code is loosely based on the Linux serial driver, written by - * Linus Torvalds, Theodore T'so and others. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Original release 10/26/00 - * - * 02/06/01 Support MOXA Industio family boards. - * 02/06/01 Support TIOCGICOUNT. - * 02/06/01 Fix the problem for connecting to serial mouse. - * 02/06/01 Fix the problem for H/W flow control. - * 02/06/01 Fix the compling warning when CONFIG_PCI - * don't be defined. - * - * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox - * . The original 1.8 code is available on www.moxa.com. - * - Fixed x86_64 cleanness - * - Fixed sleep with spinlock held in mxser_send_break - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "mxser.h" - -#define MXSER_VERSION "1.8" -#define MXSERMAJOR 174 -#define MXSERCUMAJOR 175 - -#define MXSER_EVENT_TXLOW 1 -#define MXSER_EVENT_HANGUP 2 - -#define MXSER_BOARDS 4 /* Max. boards */ -#define MXSER_PORTS 32 /* Max. ports */ -#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ -#define MXSER_ISR_PASS_LIMIT 256 - -#define MXSER_ERR_IOADDR -1 -#define MXSER_ERR_IRQ -2 -#define MXSER_ERR_IRQ_CONFLIT -3 -#define MXSER_ERR_VECTOR -4 - -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 - -#define WAKEUP_CHARS 256 - -#define UART_MCR_AFE 0x20 -#define UART_LSR_SPECIAL 0x1E - -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\ - IXON|IXOFF)) - -#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) - -#define C168_ASIC_ID 1 -#define C104_ASIC_ID 2 -#define C102_ASIC_ID 0xB -#define CI132_ASIC_ID 4 -#define CI134_ASIC_ID 3 -#define CI104J_ASIC_ID 5 - -enum { - MXSER_BOARD_C168_ISA = 1, - MXSER_BOARD_C104_ISA, - MXSER_BOARD_CI104J, - MXSER_BOARD_C168_PCI, - MXSER_BOARD_C104_PCI, - MXSER_BOARD_C102_ISA, - MXSER_BOARD_CI132, - MXSER_BOARD_CI134, - MXSER_BOARD_CP132, - MXSER_BOARD_CP114, - MXSER_BOARD_CT114, - MXSER_BOARD_CP102, - MXSER_BOARD_CP104U, - MXSER_BOARD_CP168U, - MXSER_BOARD_CP132U, - MXSER_BOARD_CP134U, - MXSER_BOARD_CP104JU, - MXSER_BOARD_RC7000, - MXSER_BOARD_CP118U, - MXSER_BOARD_CP102UL, - MXSER_BOARD_CP102U, -}; - -static char *mxser_brdname[] = { - "C168 series", - "C104 series", - "CI-104J series", - "C168H/PCI series", - "C104H/PCI series", - "C102 series", - "CI-132 series", - "CI-134 series", - "CP-132 series", - "CP-114 series", - "CT-114 series", - "CP-102 series", - "CP-104U series", - "CP-168U series", - "CP-132U series", - "CP-134U series", - "CP-104JU series", - "Moxa UC7000 Serial", - "CP-118U series", - "CP-102UL series", - "CP-102U series", -}; - -static int mxser_numports[] = { - 8, /* C168-ISA */ - 4, /* C104-ISA */ - 4, /* CI104J */ - 8, /* C168-PCI */ - 4, /* C104-PCI */ - 2, /* C102-ISA */ - 2, /* CI132 */ - 4, /* CI134 */ - 2, /* CP132 */ - 4, /* CP114 */ - 4, /* CT114 */ - 2, /* CP102 */ - 4, /* CP104U */ - 8, /* CP168U */ - 2, /* CP132U */ - 4, /* CP134U */ - 4, /* CP104JU */ - 8, /* RC7000 */ - 8, /* CP118U */ - 2, /* CP102UL */ - 2, /* CP102U */ -}; - -#define UART_TYPE_NUM 2 - -static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = { - MOXA_MUST_MU150_HWID, - MOXA_MUST_MU860_HWID -}; - -/* This is only for PCI */ -#define UART_INFO_NUM 3 -struct mxpciuart_info { - int type; - int tx_fifo; - int rx_fifo; - int xmit_fifo_size; - int rx_high_water; - int rx_trigger; - int rx_low_water; - long max_baud; -}; - -static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = { - {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L}, - {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L}, - {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} -}; - - -#ifdef CONFIG_PCI - -static struct pci_device_id mxser_pcibrds[] = { - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C168_PCI}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP114}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CT114}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP168U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP132U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP134U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP104JU}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_RC7000}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP118U}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102UL}, - {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_CP102U}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, mxser_pcibrds); - - -#endif - -typedef struct _moxa_pci_info { - unsigned short busNum; - unsigned short devNum; - struct pci_dev *pdev; /* add by Victor Yu. 06-23-2003 */ -} moxa_pci_info; - -static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; -static int ttymajor = MXSERMAJOR; -static int calloutmajor = MXSERCUMAJOR; -static int verbose = 0; - -/* Variables for insmod */ - -MODULE_AUTHOR("Casper Yang"); -MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); -module_param_array(ioaddr, int, NULL, 0); -module_param(ttymajor, int, 0); -module_param(calloutmajor, int, 0); -module_param(verbose, bool, 0); -MODULE_LICENSE("GPL"); - -struct mxser_log { - int tick; - unsigned long rxcnt[MXSER_PORTS]; - unsigned long txcnt[MXSER_PORTS]; -}; - - -struct mxser_mon { - unsigned long rxcnt; - unsigned long txcnt; - unsigned long up_rxcnt; - unsigned long up_txcnt; - int modem_status; - unsigned char hold_reason; -}; - -struct mxser_mon_ext { - unsigned long rx_cnt[32]; - unsigned long tx_cnt[32]; - unsigned long up_rxcnt[32]; - unsigned long up_txcnt[32]; - int modem_status[32]; - - long baudrate[32]; - int databits[32]; - int stopbits[32]; - int parity[32]; - int flowctrl[32]; - int fifo[32]; - int iftype[32]; -}; - -struct mxser_hwconf { - int board_type; - int ports; - int irq; - int vector; - int vector_mask; - int uart_type; - int ioaddr[MXSER_PORTS_PER_BOARD]; - int baud_base[MXSER_PORTS_PER_BOARD]; - moxa_pci_info pciInfo; - int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */ - int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */ - int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */ -}; - -struct mxser_struct { - int port; - int base; /* port base address */ - int irq; /* port using irq no. */ - int vector; /* port irq vector */ - int vectormask; /* port vector mask */ - int rx_high_water; - int rx_trigger; /* Rx fifo trigger level */ - int rx_low_water; - int baud_base; /* max. speed */ - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int xmit_fifo_size; - int custom_divisor; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ - unsigned long event; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct work_struct tqueue; - struct termios normal_termios; - struct termios callout_termios; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t delta_msr_wait; - struct async_icount icount; /* kernel counters for the 4 input interrupts */ - int timeout; - int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */ - int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */ - int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */ - unsigned char stop_rx; - unsigned char ldisc_stop_rx; - long realbaud; - struct mxser_mon mon_data; - unsigned char err_shadow; - spinlock_t slock; -}; - -struct mxser_mstatus { - tcflag_t cflag; - int cts; - int dsr; - int ri; - int dcd; -}; - -static struct mxser_mstatus GMStatus[MXSER_PORTS]; - -static int mxserBoardCAP[MXSER_BOARDS] = { - 0, 0, 0, 0 - /* 0x180, 0x280, 0x200, 0x320 */ -}; - -static struct tty_driver *mxvar_sdriver; -static struct mxser_struct mxvar_table[MXSER_PORTS]; -static struct tty_struct *mxvar_tty[MXSER_PORTS + 1]; -static struct termios *mxvar_termios[MXSER_PORTS + 1]; -static struct termios *mxvar_termios_locked[MXSER_PORTS + 1]; -static struct mxser_log mxvar_log; -static int mxvar_diagflag; -static unsigned char mxser_msr[MXSER_PORTS + 1]; -static struct mxser_mon_ext mon_data_ext; -static int mxser_set_baud_method[MXSER_PORTS + 1]; -static spinlock_t gm_lock; - -/* - * This is used to figure out the divisor speeds and the timeouts - */ - -static struct mxser_hwconf mxsercfg[MXSER_BOARDS]; - -/* - * static functions: - */ - -static void mxser_getcfg(int board, struct mxser_hwconf *hwconf); -static int mxser_init(void); - -/* static void mxser_poll(unsigned long); */ -static int mxser_get_ISA_conf(int, struct mxser_hwconf *); -static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); -static void mxser_do_softint(void *); -static int mxser_open(struct tty_struct *, struct file *); -static void mxser_close(struct tty_struct *, struct file *); -static int mxser_write(struct tty_struct *, const unsigned char *, int); -static int mxser_write_room(struct tty_struct *); -static void mxser_flush_buffer(struct tty_struct *); -static int mxser_chars_in_buffer(struct tty_struct *); -static void mxser_flush_chars(struct tty_struct *); -static void mxser_put_char(struct tty_struct *, unsigned char); -static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); -static int mxser_ioctl_special(unsigned int, void __user *); -static void mxser_throttle(struct tty_struct *); -static void mxser_unthrottle(struct tty_struct *); -static void mxser_set_termios(struct tty_struct *, struct termios *); -static void mxser_stop(struct tty_struct *); -static void mxser_start(struct tty_struct *); -static void mxser_hangup(struct tty_struct *); -static void mxser_rs_break(struct tty_struct *, int); -static irqreturn_t mxser_interrupt(int, void *); -static void mxser_receive_chars(struct mxser_struct *, int *); -static void mxser_transmit_chars(struct mxser_struct *); -static void mxser_check_modem_status(struct mxser_struct *, int); -static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); -static int mxser_startup(struct mxser_struct *); -static void mxser_shutdown(struct mxser_struct *); -static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios); -static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *); -static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *); -static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *); -static void mxser_send_break(struct mxser_struct *, int); -static int mxser_tiocmget(struct tty_struct *, struct file *); -static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int); -static int mxser_set_baud(struct mxser_struct *info, long newspd); -static void mxser_wait_until_sent(struct tty_struct *tty, int timeout); - -static void mxser_startrx(struct tty_struct *tty); -static void mxser_stoprx(struct tty_struct *tty); - - -static int CheckIsMoxaMust(int io) -{ - u8 oldmcr, hwid; - int i; - - outb(0, io + UART_LCR); - DISABLE_MOXA_MUST_ENCHANCE_MODE(io); - oldmcr = inb(io + UART_MCR); - outb(0, io + UART_MCR); - SET_MOXA_MUST_XON1_VALUE(io, 0x11); - if ((hwid = inb(io + UART_MCR)) != 0) { - outb(oldmcr, io + UART_MCR); - return MOXA_OTHER_UART; - } - - GET_MOXA_MUST_HARDWARE_ID(io, &hwid); - for (i = 0; i < UART_TYPE_NUM; i++) { - if (hwid == Gmoxa_uart_id[i]) - return (int)hwid; - } - return MOXA_OTHER_UART; -} - -/* above is modified by Victor Yu. 08-15-2002 */ - -static const struct tty_operations mxser_ops = { - .open = mxser_open, - .close = mxser_close, - .write = mxser_write, - .put_char = mxser_put_char, - .flush_chars = mxser_flush_chars, - .write_room = mxser_write_room, - .chars_in_buffer = mxser_chars_in_buffer, - .flush_buffer = mxser_flush_buffer, - .ioctl = mxser_ioctl, - .throttle = mxser_throttle, - .unthrottle = mxser_unthrottle, - .set_termios = mxser_set_termios, - .stop = mxser_stop, - .start = mxser_start, - .hangup = mxser_hangup, - .break_ctl = mxser_rs_break, - .wait_until_sent = mxser_wait_until_sent, - .tiocmget = mxser_tiocmget, - .tiocmset = mxser_tiocmset, -}; - -/* - * The MOXA Smartio/Industio serial driver boot-time initialization code! - */ - -static int __init mxser_module_init(void) -{ - int ret; - - if (verbose) - printk(KERN_DEBUG "Loading module mxser ...\n"); - ret = mxser_init(); - if (verbose) - printk(KERN_DEBUG "Done.\n"); - return ret; -} - -static void __exit mxser_module_exit(void) -{ - int i, err; - - if (verbose) - printk(KERN_DEBUG "Unloading module mxser ...\n"); - - err = tty_unregister_driver(mxvar_sdriver); - if (!err) - put_tty_driver(mxvar_sdriver); - else - printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n"); - - for (i = 0; i < MXSER_BOARDS; i++) { - struct pci_dev *pdev; - - if (mxsercfg[i].board_type == -1) - continue; - else { - pdev = mxsercfg[i].pciInfo.pdev; - free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); - if (pdev != NULL) { /* PCI */ - release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); - release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); - } else { - release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports); - release_region(mxsercfg[i].vector, 1); - } - } - } - if (verbose) - printk(KERN_DEBUG "Done.\n"); -} - -static void process_txrx_fifo(struct mxser_struct *info) -{ - int i; - - if ((info->type == PORT_16450) || (info->type == PORT_8250)) { - info->rx_trigger = 1; - info->rx_high_water = 1; - info->rx_low_water = 1; - info->xmit_fifo_size = 1; - } else { - for (i = 0; i < UART_INFO_NUM; i++) { - if (info->IsMoxaMustChipFlag == Gpci_uart_info[i].type) { - info->rx_trigger = Gpci_uart_info[i].rx_trigger; - info->rx_low_water = Gpci_uart_info[i].rx_low_water; - info->rx_high_water = Gpci_uart_info[i].rx_high_water; - info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size; - break; - } - } - } -} - -static int mxser_initbrd(int board, struct mxser_hwconf *hwconf) -{ - struct mxser_struct *info; - int retval; - int i, n; - - n = board * MXSER_PORTS_PER_BOARD; - info = &mxvar_table[n]; - /*if (verbose) */ { - printk(KERN_DEBUG " ttyM%d - ttyM%d ", - n, n + hwconf->ports - 1); - printk(" max. baud rate = %d bps.\n", - hwconf->MaxCanSetBaudRate[0]); - } - - for (i = 0; i < hwconf->ports; i++, n++, info++) { - info->port = n; - info->base = hwconf->ioaddr[i]; - info->irq = hwconf->irq; - info->vector = hwconf->vector; - info->vectormask = hwconf->vector_mask; - info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */ - info->stop_rx = 0; - info->ldisc_stop_rx = 0; - - info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag; - /* Enhance mode enabled here */ - if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) { - ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base); - } - - info->flags = ASYNC_SHARE_IRQ; - info->type = hwconf->uart_type; - info->baud_base = hwconf->baud_base[i]; - - info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i]; - - process_txrx_fifo(info); - - - info->custom_divisor = hwconf->baud_base[i] * 16; - info->close_delay = 5 * HZ / 10; - info->closing_wait = 30 * HZ; - INIT_WORK(&info->tqueue, mxser_do_softint, info); - info->normal_termios = mxvar_sdriver->init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->delta_msr_wait); - memset(&info->mon_data, 0, sizeof(struct mxser_mon)); - info->err_shadow = 0; - spin_lock_init(&info->slock); - } - /* - * Allocate the IRQ if necessary - */ - - - /* before set INT ISR, disable all int */ - for (i = 0; i < hwconf->ports; i++) { - outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, - hwconf->ioaddr[i] + UART_IER); - } - - n = board * MXSER_PORTS_PER_BOARD; - info = &mxvar_table[n]; - - retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), - "mxser", info); - if (retval) { - printk(KERN_ERR "Board %d: %s", - board, mxser_brdname[hwconf->board_type - 1]); - printk(" Request irq failed, IRQ (%d) may conflict with" - " another device.\n", info->irq); - return retval; - } - return 0; -} - -static void mxser_getcfg(int board, struct mxser_hwconf *hwconf) -{ - mxsercfg[board] = *hwconf; -} - -#ifdef CONFIG_PCI -static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf) -{ - int i, j; - /* unsigned int val; */ - unsigned int ioaddress; - struct pci_dev *pdev = hwconf->pciInfo.pdev; - - /* io address */ - hwconf->board_type = board_type; - hwconf->ports = mxser_numports[board_type - 1]; - ioaddress = pci_resource_start(pdev, 2); - request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2), - "mxser(IO)"); - - for (i = 0; i < hwconf->ports; i++) - hwconf->ioaddr[i] = ioaddress + 8 * i; - - /* vector */ - ioaddress = pci_resource_start(pdev, 3); - request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), - "mxser(vector)"); - hwconf->vector = ioaddress; - - /* irq */ - hwconf->irq = hwconf->pciInfo.pdev->irq; - - hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]); - hwconf->uart_type = PORT_16550A; - hwconf->vector_mask = 0; - - - for (i = 0; i < hwconf->ports; i++) { - for (j = 0; j < UART_INFO_NUM; j++) { - if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) { - hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud; - - /* exception....CP-102 */ - if (board_type == MXSER_BOARD_CP102) - hwconf->MaxCanSetBaudRate[i] = 921600; - break; - } - } - } - - if (hwconf->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID) { - for (i = 0; i < hwconf->ports; i++) { - if (i < 4) - hwconf->opmode_ioaddr[i] = ioaddress + 4; - else - hwconf->opmode_ioaddr[i] = ioaddress + 0x0c; - } - outb(0, ioaddress + 4); /* default set to RS232 mode */ - outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ - } - - for (i = 0; i < hwconf->ports; i++) { - hwconf->vector_mask |= (1 << i); - hwconf->baud_base[i] = 921600; - } - return 0; -} -#endif - -static int mxser_init(void) -{ - int i, m, retval, b, n; - struct pci_dev *pdev = NULL; - int index; - unsigned char busnum, devnum; - struct mxser_hwconf hwconf; - - mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); - if (!mxvar_sdriver) - return -ENOMEM; - spin_lock_init(&gm_lock); - - for (i = 0; i < MXSER_BOARDS; i++) { - mxsercfg[i].board_type = -1; - } - - printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", - MXSER_VERSION); - - /* Initialize the tty_driver structure */ - memset(mxvar_sdriver, 0, sizeof(struct tty_driver)); - mxvar_sdriver->magic = TTY_DRIVER_MAGIC; - mxvar_sdriver->name = "ttyM"; - mxvar_sdriver->major = ttymajor; - mxvar_sdriver->minor_start = 0; - mxvar_sdriver->num = MXSER_PORTS + 1; - mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; - mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; - mxvar_sdriver->init_termios = tty_std_termios; - mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; - mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(mxvar_sdriver, &mxser_ops); - mxvar_sdriver->ttys = mxvar_tty; - mxvar_sdriver->termios = mxvar_termios; - mxvar_sdriver->termios_locked = mxvar_termios_locked; - - mxvar_diagflag = 0; - memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); - memset(&mxvar_log, 0, sizeof(struct mxser_log)); - - memset(&mxser_msr, 0, sizeof(unsigned char) * (MXSER_PORTS + 1)); - memset(&mon_data_ext, 0, sizeof(struct mxser_mon_ext)); - memset(&mxser_set_baud_method, 0, sizeof(int) * (MXSER_PORTS + 1)); - memset(&hwconf, 0, sizeof(struct mxser_hwconf)); - - m = 0; - /* Start finding ISA boards here */ - for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { - int cap; - - if (!(cap = mxserBoardCAP[b])) - continue; - - retval = mxser_get_ISA_conf(cap, &hwconf); - - if (retval != 0) - printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], ioaddr[b]); - - if (retval <= 0) { - if (retval == MXSER_ERR_IRQ) - printk(KERN_ERR "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_IRQ_CONFLIT) - printk(KERN_ERR "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_VECTOR) - printk(KERN_ERR "Invalid interrupt vector, " - "board not configured\n"); - else if (retval == MXSER_ERR_IOADDR) - printk(KERN_ERR "Invalid I/O address, " - "board not configured\n"); - - continue; - } - - hwconf.pciInfo.busNum = 0; - hwconf.pciInfo.devNum = 0; - hwconf.pciInfo.pdev = NULL; - - mxser_getcfg(m, &hwconf); - /* - * init mxsercfg first, - * or mxsercfg data is not correct on ISR. - */ - /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(m, &hwconf) < 0) - continue; - - m++; - } - - /* Start finding ISA boards from module arg */ - for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { - int cap; - - if (!(cap = ioaddr[b])) - continue; - - retval = mxser_get_ISA_conf(cap, &hwconf); - - if (retval != 0) - printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], ioaddr[b]); - - if (retval <= 0) { - if (retval == MXSER_ERR_IRQ) - printk(KERN_ERR "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_IRQ_CONFLIT) - printk(KERN_ERR "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_VECTOR) - printk(KERN_ERR "Invalid interrupt vector, " - "board not configured\n"); - else if (retval == MXSER_ERR_IOADDR) - printk(KERN_ERR "Invalid I/O address, " - "board not configured\n"); - - continue; - } - - hwconf.pciInfo.busNum = 0; - hwconf.pciInfo.devNum = 0; - hwconf.pciInfo.pdev = NULL; - - mxser_getcfg(m, &hwconf); - /* - * init mxsercfg first, - * or mxsercfg data is not correct on ISR. - */ - /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(m, &hwconf) < 0) - continue; - - m++; - } - - /* start finding PCI board here */ -#ifdef CONFIG_PCI - n = ARRAY_SIZE(mxser_pcibrds) - 1; - index = 0; - b = 0; - while (b < n) { - pdev = pci_find_device(mxser_pcibrds[b].vendor, - mxser_pcibrds[b].device, pdev); - if (pdev == NULL) { - b++; - continue; - } - hwconf.pciInfo.busNum = busnum = pdev->bus->number; - hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3; - hwconf.pciInfo.pdev = pdev; - printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", - mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], - busnum, devnum >> 3); - index++; - if (m >= MXSER_BOARDS) - printk(KERN_ERR - "Too many Smartio/Industio family boards find " - "(maximum %d), board not configured\n", - MXSER_BOARDS); - else { - if (pci_enable_device(pdev)) { - printk(KERN_ERR "Moxa SmartI/O PCI enable " - "fail !\n"); - continue; - } - retval = mxser_get_PCI_conf(busnum, devnum, - (int)mxser_pcibrds[b].driver_data, - &hwconf); - if (retval < 0) { - if (retval == MXSER_ERR_IRQ) - printk(KERN_ERR - "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_IRQ_CONFLIT) - printk(KERN_ERR - "Invalid interrupt number, " - "board not configured\n"); - else if (retval == MXSER_ERR_VECTOR) - printk(KERN_ERR - "Invalid interrupt vector, " - "board not configured\n"); - else if (retval == MXSER_ERR_IOADDR) - printk(KERN_ERR - "Invalid I/O address, " - "board not configured\n"); - continue; - } - mxser_getcfg(m, &hwconf); - /* init mxsercfg first, - * or mxsercfg data is not correct on ISR. - */ - /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(m, &hwconf) < 0) - continue; - m++; - } - } -#endif - - retval = tty_register_driver(mxvar_sdriver); - if (retval) { - printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family" - " driver !\n"); - put_tty_driver(mxvar_sdriver); - - for (i = 0; i < MXSER_BOARDS; i++) { - if (mxsercfg[i].board_type == -1) - continue; - else { - free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); - /* todo: release io, vector */ - } - } - return retval; - } - - return 0; -} - -static void mxser_do_softint(void *private_) -{ - struct mxser_struct *info = private_; - struct tty_struct *tty; - - tty = info->tty; - - if (tty) { - if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) - tty_wakeup(tty); - if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) - tty_hangup(tty); - } -} - -static unsigned char mxser_get_msr(int baseaddr, int mode, int port, struct mxser_struct *info) -{ - unsigned char status = 0; - - status = inb(baseaddr + UART_MSR); - - mxser_msr[port] &= 0x0F; - mxser_msr[port] |= status; - status = mxser_msr[port]; - if (mode) - mxser_msr[port] = 0; - - return status; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int mxser_open(struct tty_struct *tty, struct file *filp) -{ - struct mxser_struct *info; - int retval, line; - - /* initialize driver_data in case something fails */ - tty->driver_data = NULL; - - line = tty->index; - if (line == MXSER_PORTS) - return 0; - if (line < 0 || line > MXSER_PORTS) - return -ENODEV; - info = mxvar_table + line; - if (!info->base) - return -ENODEV; - - tty->driver_data = info; - info->tty = tty; - /* - * Start up serial port - */ - retval = mxser_startup(info); - if (retval) - return retval; - - retval = mxser_block_til_ready(tty, filp, info); - if (retval) - return retval; - - info->count++; - - if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; - mxser_change_speed(info, NULL); - } - - info->session = current->signal->session; - info->pgrp = process_group(current); - - /* - status = mxser_get_msr(info->base, 0, info->port); - mxser_check_modem_status(info, status); - */ - -/* unmark here for very high baud rate (ex. 921600 bps) used */ - tty->low_latency = 1; - return 0; -} - -/* - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - */ -static void mxser_close(struct tty_struct *tty, struct file *filp) -{ - struct mxser_struct *info = tty->driver_data; - - unsigned long timeout; - unsigned long flags; - struct tty_ldisc *ld; - - if (tty->index == MXSER_PORTS) - return; - if (!info) - return; - - spin_lock_irqsave(&info->slock, flags); - - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&info->slock, flags); - return; - } - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk(KERN_ERR "mxser_close: bad serial port count; " - "tty->count is 1, info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk(KERN_ERR "mxser_close: bad serial port count for " - "ttys%d: %d\n", info->port, info->count); - info->count = 0; - } - if (info->count) { - spin_unlock_irqrestore(&info->slock, flags); - return; - } - info->flags |= ASYNC_CLOSING; - spin_unlock_irqrestore(&info->slock, flags); - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->IER &= ~UART_IER_RLSI; - if (info->IsMoxaMustChipFlag) - info->IER &= ~MOXA_MUST_RECV_ISR; -/* by William - info->read_status_mask &= ~UART_LSR_DR; -*/ - if (info->flags & ASYNC_INITIALIZED) { - outb(info->IER, info->base + UART_IER); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = jiffies + HZ; - while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) { - schedule_timeout_interruptible(5); - if (time_after(jiffies, timeout)) - break; - } - } - mxser_shutdown(info); - - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->flush_buffer) - ld->flush_buffer(tty); - tty_ldisc_deref(ld); - } - - tty->closing = 0; - info->event = 0; - info->tty = NULL; - if (info->blocked_open) { - if (info->close_delay) - schedule_timeout_interruptible(info->close_delay); - wake_up_interruptible(&info->open_wait); - } - - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - -} - -static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - int c, total = 0; - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - if (!info->xmit_buf) - return 0; - - while (1) { - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - total += c; - } - - if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - (info->IsMoxaMustChipFlag)) { - spin_lock_irqsave(&info->slock, flags); - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } - return total; -} - -static void mxser_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - if (!info->xmit_buf) - return; - - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) - return; - - spin_lock_irqsave(&info->slock, flags); - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; - spin_unlock_irqrestore(&info->slock, flags); - if (!tty->stopped && !(info->IER & UART_IER_THRI)) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - info->IsMoxaMustChipFlag) { - spin_lock_irqsave(&info->slock, flags); - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } -} - - -static void mxser_flush_chars(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - if (info->xmit_cnt <= 0 || - tty->stopped || - !info->xmit_buf || - (tty->hw_stopped && - (info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag) - )) - return; - - spin_lock_irqsave(&info->slock, flags); - - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - - spin_unlock_irqrestore(&info->slock, flags); -} - -static int mxser_write_room(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - int ret; - - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int mxser_chars_in_buffer(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - return info->xmit_cnt; -} - -static void mxser_flush_buffer(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - char fcr; - unsigned long flags; - - - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* below added by shinhay */ - fcr = inb(info->base + UART_FCR); - outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), - info->base + UART_FCR); - outb(fcr, info->base + UART_FCR); - - spin_unlock_irqrestore(&info->slock, flags); - /* above added by shinhay */ - - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); -} - -static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct mxser_struct *info = tty->driver_data; - int retval; - struct async_icount cprev, cnow; /* kernel counter temps */ - struct serial_icounter_struct __user *p_cuser; - unsigned long templ; - unsigned long flags; - void __user *argp = (void __user *)arg; - - if (tty->index == MXSER_PORTS) - return mxser_ioctl_special(cmd, argp); - - /* following add by Victor Yu. 01-05-2004 */ - if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { - int opmode, p; - static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; - int shiftbit; - unsigned char val, mask; - - p = info->port % 4; - if (cmd == MOXA_SET_OP_MODE) { - if (get_user(opmode, (int __user *) argp)) - return -EFAULT; - if (opmode != RS232_MODE && - opmode != RS485_2WIRE_MODE && - opmode != RS422_MODE && - opmode != RS485_4WIRE_MODE) - return -EFAULT; - mask = ModeMask[p]; - shiftbit = p * 2; - val = inb(info->opmode_ioaddr); - val &= mask; - val |= (opmode << shiftbit); - outb(val, info->opmode_ioaddr); - } else { - shiftbit = p * 2; - opmode = inb(info->opmode_ioaddr) >> shiftbit; - opmode &= OP_MODE_MASK; - if (copy_to_user(argp, &opmode, sizeof(int))) - return -EFAULT; - } - return 0; - } - /* above add by Victor Yu. 01-05-2004 */ - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - mxser_send_break(info, HZ / 4); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); - return 0; - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp); - case TIOCSSOFTCAR: - if (get_user(templ, (unsigned long __user *) argp)) - return -EFAULT; - arg = templ; - tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - return 0; - case TIOCGSERIAL: - return mxser_get_serial_info(info, argp); - case TIOCSSERIAL: - return mxser_set_serial_info(info, argp); - case TIOCSERGETLSR: /* Get line status register */ - return mxser_get_lsr_info(info, argp); - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: { - DECLARE_WAITQUEUE(wait, current); - int ret; - spin_lock_irqsave(&info->slock, flags); - cprev = info->icount; /* note the counters on entry */ - spin_unlock_irqrestore(&info->slock, flags); - - add_wait_queue(&info->delta_msr_wait, &wait); - while (1) { - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->slock, flags); - - set_current_state(TASK_INTERRUPTIBLE); - if (((arg & TIOCM_RNG) && - (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && - (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && - (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && - (cnow.cts != cprev.cts))) { - ret = 0; - break; - } - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - cprev = cnow; - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->delta_msr_wait, &wait); - break; - } - /* NOTREACHED */ - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->slock, flags); - p_cuser = argp; - /* modified by casper 1/11/2000 */ - if (put_user(cnow.frame, &p_cuser->frame)) - return -EFAULT; - if (put_user(cnow.brk, &p_cuser->brk)) - return -EFAULT; - if (put_user(cnow.overrun, &p_cuser->overrun)) - return -EFAULT; - if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) - return -EFAULT; - if (put_user(cnow.parity, &p_cuser->parity)) - return -EFAULT; - if (put_user(cnow.rx, &p_cuser->rx)) - return -EFAULT; - if (put_user(cnow.tx, &p_cuser->tx)) - return -EFAULT; - put_user(cnow.cts, &p_cuser->cts); - put_user(cnow.dsr, &p_cuser->dsr); - put_user(cnow.rng, &p_cuser->rng); - put_user(cnow.dcd, &p_cuser->dcd); - return 0; - case MOXA_HighSpeedOn: - return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); - case MOXA_SDS_RSTICOUNTER: { - info->mon_data.rxcnt = 0; - info->mon_data.txcnt = 0; - return 0; - } -/* (above) added by James. */ - case MOXA_ASPP_SETBAUD:{ - long baud; - if (get_user(baud, (long __user *)argp)) - return -EFAULT; - mxser_set_baud(info, baud); - return 0; - } - case MOXA_ASPP_GETBAUD: - if (copy_to_user(argp, &info->realbaud, sizeof(long))) - return -EFAULT; - - return 0; - - case MOXA_ASPP_OQUEUE:{ - int len, lsr; - - len = mxser_chars_in_buffer(tty); - - lsr = inb(info->base + UART_LSR) & UART_LSR_TEMT; - - len += (lsr ? 0 : 1); - - if (copy_to_user(argp, &len, sizeof(int))) - return -EFAULT; - - return 0; - } - case MOXA_ASPP_MON: { - int mcr, status; - - /* info->mon_data.ser_param = tty->termios->c_cflag; */ - - status = mxser_get_msr(info->base, 1, info->port, info); - mxser_check_modem_status(info, status); - - mcr = inb(info->base + UART_MCR); - if (mcr & MOXA_MUST_MCR_XON_FLAG) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; - - if (mcr & MOXA_MUST_MCR_TX_XON) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - - if (info->tty->hw_stopped) - info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; - else - info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; - - if (copy_to_user(argp, &info->mon_data, - sizeof(struct mxser_mon))) - return -EFAULT; - - return 0; - } - - case MOXA_ASPP_LSTATUS: { - if (copy_to_user(argp, &info->err_shadow, - sizeof(unsigned char))) - return -EFAULT; - - info->err_shadow = 0; - return 0; - } - case MOXA_SET_BAUD_METHOD: { - int method; - - if (get_user(method, (int __user *)argp)) - return -EFAULT; - mxser_set_baud_method[info->port] = method; - if (copy_to_user(argp, &method, sizeof(int))) - return -EFAULT; - - return 0; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -#ifndef CMSPAR -#define CMSPAR 010000000000 -#endif - -static int mxser_ioctl_special(unsigned int cmd, void __user *argp) -{ - int i, result, status; - - switch (cmd) { - case MOXA_GET_CONF: - if (copy_to_user(argp, mxsercfg, - sizeof(struct mxser_hwconf) * 4)) - return -EFAULT; - return 0; - case MOXA_GET_MAJOR: - if (copy_to_user(argp, &ttymajor, sizeof(int))) - return -EFAULT; - return 0; - - case MOXA_GET_CUMAJOR: - if (copy_to_user(argp, &calloutmajor, sizeof(int))) - return -EFAULT; - return 0; - - case MOXA_CHKPORTENABLE: - result = 0; - for (i = 0; i < MXSER_PORTS; i++) { - if (mxvar_table[i].base) - result |= (1 << i); - } - return put_user(result, (unsigned long __user *)argp); - case MOXA_GETDATACOUNT: - if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) - return -EFAULT; - return 0; - case MOXA_GETMSTATUS: - for (i = 0; i < MXSER_PORTS; i++) { - GMStatus[i].ri = 0; - if (!mxvar_table[i].base) { - GMStatus[i].dcd = 0; - GMStatus[i].dsr = 0; - GMStatus[i].cts = 0; - continue; - } - - if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios) - GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag; - else - GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag; - - status = inb(mxvar_table[i].base + UART_MSR); - if (status & 0x80 /*UART_MSR_DCD */ ) - GMStatus[i].dcd = 1; - else - GMStatus[i].dcd = 0; - - if (status & 0x20 /*UART_MSR_DSR */ ) - GMStatus[i].dsr = 1; - else - GMStatus[i].dsr = 0; - - - if (status & 0x10 /*UART_MSR_CTS */ ) - GMStatus[i].cts = 1; - else - GMStatus[i].cts = 0; - } - if (copy_to_user(argp, GMStatus, - sizeof(struct mxser_mstatus) * MXSER_PORTS)) - return -EFAULT; - return 0; - case MOXA_ASPP_MON_EXT: { - int status; - int opmode, p; - int shiftbit; - unsigned cflag, iflag; - - for (i = 0; i < MXSER_PORTS; i++) { - if (!mxvar_table[i].base) - continue; - - status = mxser_get_msr(mxvar_table[i].base, 0, - i, &(mxvar_table[i])); - /* - mxser_check_modem_status(&mxvar_table[i], - status); - */ - if (status & UART_MSR_TERI) - mxvar_table[i].icount.rng++; - if (status & UART_MSR_DDSR) - mxvar_table[i].icount.dsr++; - if (status & UART_MSR_DDCD) - mxvar_table[i].icount.dcd++; - if (status & UART_MSR_DCTS) - mxvar_table[i].icount.cts++; - - mxvar_table[i].mon_data.modem_status = status; - mon_data_ext.rx_cnt[i] = mxvar_table[i].mon_data.rxcnt; - mon_data_ext.tx_cnt[i] = mxvar_table[i].mon_data.txcnt; - mon_data_ext.up_rxcnt[i] = mxvar_table[i].mon_data.up_rxcnt; - mon_data_ext.up_txcnt[i] = mxvar_table[i].mon_data.up_txcnt; - mon_data_ext.modem_status[i] = mxvar_table[i].mon_data.modem_status; - mon_data_ext.baudrate[i] = mxvar_table[i].realbaud; - - if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios) { - cflag = mxvar_table[i].normal_termios.c_cflag; - iflag = mxvar_table[i].normal_termios.c_iflag; - } else { - cflag = mxvar_table[i].tty->termios->c_cflag; - iflag = mxvar_table[i].tty->termios->c_iflag; - } - - mon_data_ext.databits[i] = cflag & CSIZE; - - mon_data_ext.stopbits[i] = cflag & CSTOPB; - - mon_data_ext.parity[i] = cflag & (PARENB | PARODD | CMSPAR); - - mon_data_ext.flowctrl[i] = 0x00; - - if (cflag & CRTSCTS) - mon_data_ext.flowctrl[i] |= 0x03; - - if (iflag & (IXON | IXOFF)) - mon_data_ext.flowctrl[i] |= 0x0C; - - if (mxvar_table[i].type == PORT_16550A) - mon_data_ext.fifo[i] = 1; - else - mon_data_ext.fifo[i] = 0; - - p = i % 4; - shiftbit = p * 2; - opmode = inb(mxvar_table[i].opmode_ioaddr) >> shiftbit; - opmode &= OP_MODE_MASK; - - mon_data_ext.iftype[i] = opmode; - - } - if (copy_to_user(argp, &mon_data_ext, sizeof(struct mxser_mon_ext))) - return -EFAULT; - - return 0; - - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void mxser_stoprx(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - /* unsigned long flags; */ - - info->ldisc_stop_rx = 1; - if (I_IXOFF(tty)) { - /* MX_LOCK(&info->slock); */ - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag) { - info->IER &= ~MOXA_MUST_RECV_ISR; - outb(info->IER, info->base + UART_IER); - } else { - /* above add by Victor Yu. 09-02-2002 */ - info->x_char = STOP_CHAR(tty); - /* mask by Victor Yu. 09-02-2002 */ - /* outb(info->IER, 0); */ - outb(0, info->base + UART_IER); - info->IER |= UART_IER_THRI; - /* force Tx interrupt */ - outb(info->IER, info->base + UART_IER); - } /* add by Victor Yu. 09-02-2002 */ - /* MX_UNLOCK(&info->slock); */ - } - - if (info->tty->termios->c_cflag & CRTSCTS) { - /* MX_LOCK(&info->slock); */ - info->MCR &= ~UART_MCR_RTS; - outb(info->MCR, info->base + UART_MCR); - /* MX_UNLOCK(&info->slock); */ - } -} - -static void mxser_startrx(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - /* unsigned long flags; */ - - info->ldisc_stop_rx = 0; - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else { - /* MX_LOCK(&info->slock); */ - - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag) { - info->IER |= MOXA_MUST_RECV_ISR; - outb(info->IER, info->base + UART_IER); - } else { - /* above add by Victor Yu. 09-02-2002 */ - - info->x_char = START_CHAR(tty); - /* mask by Victor Yu. 09-02-2002 */ - /* outb(info->IER, 0); */ - /* add by Victor Yu. 09-02-2002 */ - outb(0, info->base + UART_IER); - /* force Tx interrupt */ - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } /* add by Victor Yu. 09-02-2002 */ - /* MX_UNLOCK(&info->slock); */ - } - } - - if (info->tty->termios->c_cflag & CRTSCTS) { - /* MX_LOCK(&info->slock); */ - info->MCR |= UART_MCR_RTS; - outb(info->MCR, info->base + UART_MCR); - /* MX_UNLOCK(&info->slock); */ - } -} - -/* - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - */ -static void mxser_throttle(struct tty_struct *tty) -{ - /* struct mxser_struct *info = tty->driver_data; */ - /* unsigned long flags; */ - - /* MX_LOCK(&info->slock); */ - mxser_stoprx(tty); - /* MX_UNLOCK(&info->slock); */ -} - -static void mxser_unthrottle(struct tty_struct *tty) -{ - /* struct mxser_struct *info = tty->driver_data; */ - /* unsigned long flags; */ - - /* MX_LOCK(&info->slock); */ - mxser_startrx(tty); - /* MX_UNLOCK(&info->slock); */ -} - -static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - if ((tty->termios->c_cflag != old_termios->c_cflag) || - (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { - - mxser_change_speed(info, old_termios); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - mxser_start(tty); - } - } - -/* Handle sw stopped */ - if ((old_termios->c_iflag & IXON) && - !(tty->termios->c_iflag & IXON)) { - tty->stopped = 0; - - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag) { - spin_lock_irqsave(&info->slock, flags); - DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); - spin_unlock_irqrestore(&info->slock, flags); - } - /* above add by Victor Yu. 09-02-2002 */ - - mxser_start(tty); - } -} - -/* - * mxser_stop() and mxser_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - */ -static void mxser_stop(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - if (info->IER & UART_IER_THRI) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - spin_unlock_irqrestore(&info->slock, flags); -} - -static void mxser_start(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - spin_unlock_irqrestore(&info->slock, flags); -} - -/* - * mxser_wait_until_sent() --- wait until the transmitter is empty - */ -static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long orig_jiffies, char_time; - int lsr; - - if (info->type == PORT_UNKNOWN) - return; - - if (info->xmit_fifo_size == 0) - return; /* Just in case.... */ - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ - if (!timeout || timeout > 2 * info->timeout) - timeout = 2 * info->timeout; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", - timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif - schedule_timeout_interruptible(char_time); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - set_current_state(TASK_RUNNING); - -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - - -/* - * This routine is called by tty_hangup() when a hangup is signaled. - */ -void mxser_hangup(struct tty_struct *tty) -{ - struct mxser_struct *info = tty->driver_data; - - mxser_flush_buffer(tty); - mxser_shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); -} - - -/* added by James 03-12-2004. */ -/* - * mxser_rs_break() --- routine which turns the break handling on or off - */ -static void mxser_rs_break(struct tty_struct *tty, int break_state) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - if (break_state == -1) - outb(inb(info->base + UART_LCR) | UART_LCR_SBC, - info->base + UART_LCR); - else - outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, - info->base + UART_LCR); - spin_unlock_irqrestore(&info->slock, flags); -} - -/* (above) added by James. */ - - -/* - * This is the serial driver's generic interrupt routine - */ -static irqreturn_t mxser_interrupt(int irq, void *dev_id) -{ - int status, iir, i; - struct mxser_struct *info; - struct mxser_struct *port; - int max, irqbits, bits, msr; - int pass_counter = 0; - int handled = IRQ_NONE; - - port = NULL; - /* spin_lock(&gm_lock); */ - - for (i = 0; i < MXSER_BOARDS; i++) { - if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { - port = dev_id; - break; - } - } - - if (i == MXSER_BOARDS) - goto irq_stop; - if (port == 0) - goto irq_stop; - max = mxser_numports[mxsercfg[i].board_type - 1]; - while (1) { - irqbits = inb(port->vector) & port->vectormask; - if (irqbits == port->vectormask) - break; - - handled = IRQ_HANDLED; - for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == port->vectormask) - break; - if (bits & irqbits) - continue; - info = port + i; - - /* following add by Victor Yu. 09-13-2002 */ - iir = inb(info->base + UART_IIR); - if (iir & UART_IIR_NO_INT) - continue; - iir &= MOXA_MUST_IIR_MASK; - if (!info->tty) { - status = inb(info->base + UART_LSR); - outb(0x27, info->base + UART_FCR); - inb(info->base + UART_MSR); - continue; - } - /* above add by Victor Yu. 09-13-2002 */ - /* - if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) { - info->IER |= MOXA_MUST_RECV_ISR; - outb(info->IER, info->base + UART_IER); - } - */ - - - /* mask by Victor Yu. 09-13-2002 - if ( !info->tty || - (inb(info->base + UART_IIR) & UART_IIR_NO_INT) ) - continue; - */ - /* mask by Victor Yu. 09-02-2002 - status = inb(info->base + UART_LSR) & info->read_status_mask; - */ - - /* following add by Victor Yu. 09-02-2002 */ - status = inb(info->base + UART_LSR); - - if (status & UART_LSR_PE) - info->err_shadow |= NPPI_NOTIFY_PARITY; - if (status & UART_LSR_FE) - info->err_shadow |= NPPI_NOTIFY_FRAMING; - if (status & UART_LSR_OE) - info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN; - if (status & UART_LSR_BI) - info->err_shadow |= NPPI_NOTIFY_BREAK; - - if (info->IsMoxaMustChipFlag) { - /* - if ( (status & 0x02) && !(status & 0x01) ) { - outb(info->base+UART_FCR, 0x23); - continue; - } - */ - if (iir == MOXA_MUST_IIR_GDA || - iir == MOXA_MUST_IIR_RDA || - iir == MOXA_MUST_IIR_RTO || - iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(info, &status); - - } else { - /* above add by Victor Yu. 09-02-2002 */ - - status &= info->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(info, &status); - } - msr = inb(info->base + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) { - mxser_check_modem_status(info, msr); - } - /* following add by Victor Yu. 09-13-2002 */ - if (info->IsMoxaMustChipFlag) { - if ((iir == 0x02) && (status & UART_LSR_THRE)) { - mxser_transmit_chars(info); - } - } else { - /* above add by Victor Yu. 09-13-2002 */ - - if (status & UART_LSR_THRE) { -/* 8-2-99 by William - if ( info->x_char || (info->xmit_cnt > 0) ) -*/ - mxser_transmit_chars(info); - } - } - } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { - break; /* Prevent infinite loops */ - } - } - - irq_stop: - /* spin_unlock(&gm_lock); */ - return handled; -} - -static void mxser_receive_chars(struct mxser_struct *info, int *status) -{ - struct tty_struct *tty = info->tty; - unsigned char ch, gdl; - int ignored = 0; - int cnt = 0; - int recv_room; - int max = 256; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - - recv_room = tty->receive_room; - if ((recv_room == 0) && (!info->ldisc_stop_rx)) { - /* mxser_throttle(tty); */ - mxser_stoprx(tty); - /* return; */ - } - - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) { - - if (*status & UART_LSR_SPECIAL) { - goto intr_old; - } - /* following add by Victor Yu. 02-11-2004 */ - if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && - (*status & MOXA_MUST_LSR_RERR)) - goto intr_old; - /* above add by Victor Yu. 02-14-2004 */ - if (*status & MOXA_MUST_LSR_RERR) - goto intr_old; - - gdl = inb(info->base + MOXA_MUST_GDL_REGISTER); - - /* add by Victor Yu. 02-11-2004 */ - if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID) - gdl &= MOXA_MUST_GDL_MASK; - if (gdl >= recv_room) { - if (!info->ldisc_stop_rx) { - /* mxser_throttle(tty); */ - mxser_stoprx(tty); - } - /* return; */ - } - while (gdl--) { - ch = inb(info->base + UART_RX); - tty_insert_flip_char(tty, ch, 0); - cnt++; - /* - if ((cnt >= HI_WATER) && (info->stop_rx == 0)) { - mxser_stoprx(tty); - info->stop_rx = 1; - break; - } */ - } - goto end_intr; - } - intr_old: - /* above add by Victor Yu. 09-02-2002 */ - - do { - if (max-- < 0) - break; - /* - if ((cnt >= HI_WATER) && (info->stop_rx == 0)) { - mxser_stoprx(tty); - info->stop_rx=1; - break; - } - */ - - ch = inb(info->base + UART_RX); - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ ) - outb(0x23, info->base + UART_FCR); - *status &= info->read_status_mask; - /* above add by Victor Yu. 09-02-2002 */ - if (*status & info->ignore_status_mask) { - if (++ignored > 100) - break; - } else { - char flag = 0; - if (*status & UART_LSR_SPECIAL) { - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; -/* added by casper 1/11/2000 */ - info->icount.brk++; -/* */ - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (*status & UART_LSR_PE) { - flag = TTY_PARITY; -/* added by casper 1/11/2000 */ - info->icount.parity++; -/* */ - } else if (*status & UART_LSR_FE) { - flag = TTY_FRAME; -/* added by casper 1/11/2000 */ - info->icount.frame++; -/* */ - } else if (*status & UART_LSR_OE) { - flag = TTY_OVERRUN; -/* added by casper 1/11/2000 */ - info->icount.overrun++; -/* */ - } - } - tty_insert_flip_char(tty, ch, flag); - cnt++; - if (cnt >= recv_room) { - if (!info->ldisc_stop_rx) { - /* mxser_throttle(tty); */ - mxser_stoprx(tty); - } - break; - } - - } - - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag) - break; - /* above add by Victor Yu. 09-02-2002 */ - - /* mask by Victor Yu. 09-02-2002 - *status = inb(info->base + UART_LSR) & info->read_status_mask; - */ - /* following add by Victor Yu. 09-02-2002 */ - *status = inb(info->base + UART_LSR); - /* above add by Victor Yu. 09-02-2002 */ - } while (*status & UART_LSR_DR); - -end_intr: /* add by Victor Yu. 09-02-2002 */ - mxvar_log.rxcnt[info->port] += cnt; - info->mon_data.rxcnt += cnt; - info->mon_data.up_rxcnt += cnt; - spin_unlock_irqrestore(&info->slock, flags); - - tty_flip_buffer_push(tty); -} - -static void mxser_transmit_chars(struct mxser_struct *info) -{ - int count, cnt; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - - if (info->x_char) { - outb(info->x_char, info->base + UART_TX); - info->x_char = 0; - mxvar_log.txcnt[info->port]++; - info->mon_data.txcnt++; - info->mon_data.up_txcnt++; - -/* added by casper 1/11/2000 */ - info->icount.tx++; -/* */ - spin_unlock_irqrestore(&info->slock, flags); - return; - } - - if (info->xmit_buf == 0) { - spin_unlock_irqrestore(&info->slock, flags); - return; - } - - if ((info->xmit_cnt <= 0) || info->tty->stopped || - (info->tty->hw_stopped && - (info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag))) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - return; - } - - cnt = info->xmit_cnt; - count = info->xmit_fifo_size; - do { - outb(info->xmit_buf[info->xmit_tail++], - info->base + UART_TX); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); - if (--info->xmit_cnt <= 0) - break; - } while (--count > 0); - mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt); - -/* added by James 03-12-2004. */ - info->mon_data.txcnt += (cnt - info->xmit_cnt); - info->mon_data.up_txcnt += (cnt - info->xmit_cnt); -/* (above) added by James. */ - -/* added by casper 1/11/2000 */ - info->icount.tx += (cnt - info->xmit_cnt); -/* */ - - if (info->xmit_cnt < WAKEUP_CHARS) { - set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_work(&info->tqueue); - } - if (info->xmit_cnt <= 0) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - spin_unlock_irqrestore(&info->slock, flags); -} - -static void mxser_check_modem_status(struct mxser_struct *info, int status) -{ - /* update input line counters */ - if (status & UART_MSR_TERI) - info->icount.rng++; - if (status & UART_MSR_DDSR) - info->icount.dsr++; - if (status & UART_MSR_DDCD) - info->icount.dcd++; - if (status & UART_MSR_DCTS) - info->icount.cts++; - info->mon_data.modem_status = status; - wake_up_interruptible(&info->delta_msr_wait); - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - schedule_work(&info->tqueue); - } - - if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { - if (status & UART_MSR_CTS) { - info->tty->hw_stopped = 0; - - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_work(&info->tqueue); } - } else { - if (!(status & UART_MSR_CTS)) { - info->tty->hw_stopped = 1; - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - } - } - } -} - -static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - unsigned long flags; - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * mxser_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); - - spin_lock_irqsave(&info->slock, flags); - if (!tty_hung_up_p(filp)) - info->count--; - spin_unlock_irqrestore(&info->slock, flags); - info->blocked_open++; - while (1) { - spin_lock_irqsave(&info->slock, flags); - outb(inb(info->base + UART_MCR) | - UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || - (inb(info->base + UART_MSR) & UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int mxser_startup(struct mxser_struct *info) -{ - unsigned long page; - unsigned long flags; - - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - spin_lock_irqsave(&info->slock, flags); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - spin_unlock_irqrestore(&info->slock, flags); - return 0; - } - - if (!info->base || !info->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - spin_unlock_irqrestore(&info->slock, flags); - return 0; - } - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *) page; - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in mxser_change_speed()) - */ - if (info->IsMoxaMustChipFlag) - outb((UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT | - MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR); - else - outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), - info->base + UART_FCR); - - /* - * At this point there's no way the LSR could still be 0xFF; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (inb(info->base + UART_LSR) == 0xff) { - spin_unlock_irqrestore(&info->slock, flags); - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - return 0; - } else - return -ENODEV; - } - - /* - * Clear the interrupt registers. - */ - (void) inb(info->base + UART_LSR); - (void) inb(info->base + UART_RX); - (void) inb(info->base + UART_IIR); - (void) inb(info->base + UART_MSR); - - /* - * Now, initialize the UART - */ - outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */ - info->MCR = UART_MCR_DTR | UART_MCR_RTS; - outb(info->MCR, info->base + UART_MCR); - - /* - * Finally, enable interrupts - */ - info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - /* info->IER = UART_IER_RLSI | UART_IER_RDI; */ - - /* following add by Victor Yu. 08-30-2002 */ - if (info->IsMoxaMustChipFlag) - info->IER |= MOXA_MUST_IER_EGDAI; - /* above add by Victor Yu. 08-30-2002 */ - outb(info->IER, info->base + UART_IER); /* enable interrupts */ - - /* - * And clear the interrupt registers again for luck. - */ - (void) inb(info->base + UART_LSR); - (void) inb(info->base + UART_RX); - (void) inb(info->base + UART_IIR); - (void) inb(info->base + UART_MSR); - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * and set the speed of the serial port - */ - spin_unlock_irqrestore(&info->slock, flags); - mxser_change_speed(info, NULL); - - info->flags |= ASYNC_INITIALIZED; - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts maybe disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void mxser_shutdown(struct mxser_struct *info) -{ - unsigned long flags; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - spin_lock_irqsave(&info->slock, flags); - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - wake_up_interruptible(&info->delta_msr_wait); - - /* - * Free the IRQ, if necessary - */ - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; - } - - info->IER = 0; - outb(0x00, info->base + UART_IER); - - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); - outb(info->MCR, info->base + UART_MCR); - - /* clear Rx/Tx FIFO's */ - /* following add by Victor Yu. 08-30-2002 */ - if (info->IsMoxaMustChipFlag) - outb((UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT | - MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR); - else - /* above add by Victor Yu. 08-30-2002 */ - outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), - info->base + UART_FCR); - - /* read data port to reset things */ - (void) inb(info->base + UART_RX); - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - - /* following add by Victor Yu. 09-23-2002 */ - if (info->IsMoxaMustChipFlag) - SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base); - /* above add by Victor Yu. 09-23-2002 */ - - spin_unlock_irqrestore(&info->slock, flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios) -{ - unsigned cflag, cval, fcr; - int ret = 0; - unsigned char status; - long baud; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return ret; - cflag = info->tty->termios->c_cflag; - if (!(info->base)) - return ret; - -#ifndef B921600 -#define B921600 (B460800 +1) -#endif - if (mxser_set_baud_method[info->port] == 0) { - baud = tty_get_baud_rate(info->tty); - mxser_set_baud(info, baud); - } - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - cval = 0x00; - break; - case CS6: - cval = 0x01; - break; - case CS7: - cval = 0x02; - break; - case CS8: - cval = 0x03; - break; - default: - cval = 0x00; - break; /* too keep GCC shut... */ - } - if (cflag & CSTOPB) - cval |= 0x04; - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; - if (cflag & CMSPAR) - cval |= UART_LCR_SPAR; - - if ((info->type == PORT_8250) || (info->type == PORT_16450)) { - if (info->IsMoxaMustChipFlag) { - fcr = UART_FCR_ENABLE_FIFO; - fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - SET_MOXA_MUST_FIFO_VALUE(info); - } else - fcr = 0; - } else { - fcr = UART_FCR_ENABLE_FIFO; - /* following add by Victor Yu. 08-30-2002 */ - if (info->IsMoxaMustChipFlag) { - fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - SET_MOXA_MUST_FIFO_VALUE(info); - } else { - /* above add by Victor Yu. 08-30-2002 */ - switch (info->rx_trigger) { - case 1: - fcr |= UART_FCR_TRIGGER_1; - break; - case 4: - fcr |= UART_FCR_TRIGGER_4; - break; - case 8: - fcr |= UART_FCR_TRIGGER_8; - break; - default: - fcr |= UART_FCR_TRIGGER_14; - break; - } - } - } - - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - info->MCR &= ~UART_MCR_AFE; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) { - info->MCR |= UART_MCR_AFE; - /* status = mxser_get_msr(info->base, 0, info->port); */ -/* - save_flags(flags); - cli(); - status = inb(baseaddr + UART_MSR); - restore_flags(flags); -*/ - /* mxser_check_modem_status(info, status); */ - } else { - /* status = mxser_get_msr(info->base, 0, info->port); */ - /* MX_LOCK(&info->slock); */ - status = inb(info->base + UART_MSR); - /* MX_UNLOCK(&info->slock); */ - if (info->tty->hw_stopped) { - if (status & UART_MSR_CTS) { - info->tty->hw_stopped = 0; - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { - info->IER |= UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_work(&info->tqueue); } - } else { - if (!(status & UART_MSR_CTS)) { - info->tty->hw_stopped = 1; - if ((info->type != PORT_16550A) && - (!info->IsMoxaMustChipFlag)) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->base + UART_IER); - } - } - } - } - } else { - info->flags &= ~ASYNC_CTS_FLOW; - } - outb(info->MCR, info->base + UART_MCR); - if (cflag & CLOCAL) { - info->flags &= ~ASYNC_CHECK_CD; - } else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - outb(info->IER, info->base + UART_IER); - - /* - * Set up parity check flag - */ - info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->tty)) - info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) - info->read_status_mask |= UART_LSR_BI; - - info->ignore_status_mask = 0; - - if (I_IGNBRK(info->tty)) { - info->ignore_status_mask |= UART_LSR_BI; - info->read_status_mask |= UART_LSR_BI; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->tty)) { - info->ignore_status_mask |= - UART_LSR_OE | - UART_LSR_PE | - UART_LSR_FE; - info->read_status_mask |= - UART_LSR_OE | - UART_LSR_PE | - UART_LSR_FE; - } - } - /* following add by Victor Yu. 09-02-2002 */ - if (info->IsMoxaMustChipFlag) { - spin_lock_irqsave(&info->slock, flags); - SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty)); - SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty)); - if (I_IXON(info->tty)) { - ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); - } else { - DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); - } - if (I_IXOFF(info->tty)) { - ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base); - } else { - DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base); - } - /* - if ( I_IXANY(info->tty) ) { - info->MCR |= MOXA_MUST_MCR_XON_ANY; - ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base); - } else { - info->MCR &= ~MOXA_MUST_MCR_XON_ANY; - DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base); - } - */ - spin_unlock_irqrestore(&info->slock, flags); - } - /* above add by Victor Yu. 09-02-2002 */ - - - outb(fcr, info->base + UART_FCR); /* set fcr */ - outb(cval, info->base + UART_LCR); - - return ret; -} - - -static int mxser_set_baud(struct mxser_struct *info, long newspd) -{ - int quot = 0; - unsigned char cval; - int ret = 0; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return ret; - - if (!(info->base)) - return ret; - - if (newspd > info->MaxCanSetBaudRate) - return 0; - - info->realbaud = newspd; - if (newspd == 134) { - quot = (2 * info->baud_base / 269); - } else if (newspd) { - quot = info->baud_base / newspd; - if (quot == 0) - quot = 1; - } else { - quot = 0; - } - - info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); - info->timeout += HZ / 50; /* Add .02 seconds of slop */ - - if (quot) { - spin_lock_irqsave(&info->slock, flags); - info->MCR |= UART_MCR_DTR; - outb(info->MCR, info->base + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); - } else { - spin_lock_irqsave(&info->slock, flags); - info->MCR &= ~UART_MCR_DTR; - outb(info->MCR, info->base + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); - return ret; - } - - cval = inb(info->base + UART_LCR); - - outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */ - - outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */ - outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */ - outb(cval, info->base + UART_LCR); /* reset DLAB */ - - - return ret; -} - -/* - * ------------------------------------------------------------ - * friends of mxser_ioctl() - * ------------------------------------------------------------ - */ -static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->port; - tmp.port = info->base; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - tmp.hub6 = 0; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info) -{ - struct serial_struct new_serial; - unsigned int flags; - int retval = 0; - - if (!new_info || !info->base) - return -EFAULT; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; - - if ((new_serial.irq != info->irq) || - (new_serial.port != info->base) || - (new_serial.custom_divisor != info->custom_divisor) || - (new_serial.baud_base != info->baud_base)) - return -EPERM; - - flags = info->flags & ASYNC_SPD_MASK; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - } else { - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->close_delay = new_serial.close_delay * HZ / 100; - info->closing_wait = new_serial.closing_wait * HZ / 100; - info->tty->low_latency = - (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */ - } - - /* added by casper, 3/17/2000, for mouse */ - info->type = new_serial.type; - - process_txrx_fifo(info); - - if (info->flags & ASYNC_INITIALIZED) { - if (flags != (info->flags & ASYNC_SPD_MASK)) { - mxser_change_speed(info, NULL); - } - } else { - retval = mxser_startup(info); - } - return retval; -} - -/* - * mxser_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 int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value) -{ - unsigned char status; - unsigned int result; - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); - status = inb(info->base + UART_LSR); - spin_unlock_irqrestore(&info->slock, flags); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result, value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void mxser_send_break(struct mxser_struct *info, int duration) -{ - unsigned long flags; - - if (!info->base) - return; - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&info->slock, flags); - outb(inb(info->base + UART_LCR) | UART_LCR_SBC, - info->base + UART_LCR); - spin_unlock_irqrestore(&info->slock, flags); - schedule_timeout(duration); - spin_lock_irqsave(&info->slock, flags); - outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, - info->base + UART_LCR); - spin_unlock_irqrestore(&info->slock, flags); -} - -static int mxser_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct mxser_struct *info = tty->driver_data; - unsigned char control, status; - unsigned long flags; - - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - control = info->MCR; - - spin_lock_irqsave(&info->slock, flags); - status = inb(info->base + UART_MSR); - if (status & UART_MSR_ANY_DELTA) - mxser_check_modem_status(info, status); - spin_unlock_irqrestore(&info->slock, flags); - return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | - ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | - ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | - ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | - ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | - ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -} - -static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) -{ - struct mxser_struct *info = tty->driver_data; - unsigned long flags; - - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - spin_lock_irqsave(&info->slock, flags); - - if (set & TIOCM_RTS) - info->MCR |= UART_MCR_RTS; - if (set & TIOCM_DTR) - info->MCR |= UART_MCR_DTR; - - if (clear & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; - - outb(info->MCR, info->base + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); - return 0; -} - - -static int mxser_read_register(int, unsigned short *); -static int mxser_program_mode(int); -static void mxser_normal_mode(int); - -static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf) -{ - int id, i, bits; - unsigned short regs[16], irq; - unsigned char scratch, scratch2; - - hwconf->IsMoxaMustChipFlag = MOXA_OTHER_UART; - - id = mxser_read_register(cap, regs); - if (id == C168_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_C168_ISA; - hwconf->ports = 8; - } else if (id == C104_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_C104_ISA; - hwconf->ports = 4; - } else if (id == C102_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_C102_ISA; - hwconf->ports = 2; - } else if (id == CI132_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_CI132; - hwconf->ports = 2; - } else if (id == CI134_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_CI134; - hwconf->ports = 4; - } else if (id == CI104J_ASIC_ID) { - hwconf->board_type = MXSER_BOARD_CI104J; - hwconf->ports = 4; - } else - return 0; - - irq = 0; - if (hwconf->ports == 2) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - if (irq != (regs[9] & 0xFF00)) - return MXSER_ERR_IRQ_CONFLIT; - } else if (hwconf->ports == 4) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if (irq != regs[9]) - return MXSER_ERR_IRQ_CONFLIT; - } else if (hwconf->ports == 8) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if ((irq != regs[9]) || (irq != regs[10])) - return MXSER_ERR_IRQ_CONFLIT; - } - - if (!irq) - return MXSER_ERR_IRQ; - hwconf->irq = ((int)(irq & 0xF000) >> 12); - for (i = 0; i < 8; i++) - hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8; - if ((regs[12] & 0x80) == 0) - return MXSER_ERR_VECTOR; - hwconf->vector = (int)regs[11]; /* interrupt vector */ - if (id == 1) - hwconf->vector_mask = 0x00FF; - else - hwconf->vector_mask = 0x000F; - for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { - if (regs[12] & bits) { - hwconf->baud_base[i] = 921600; - hwconf->MaxCanSetBaudRate[i] = 921600; /* add by Victor Yu. 09-04-2002 */ - } else { - hwconf->baud_base[i] = 115200; - hwconf->MaxCanSetBaudRate[i] = 115200; /* add by Victor Yu. 09-04-2002 */ - } - } - scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); - outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); - outb(0, cap + UART_EFR); /* EFR is the same as FCR */ - outb(scratch2, cap + UART_LCR); - outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); - scratch = inb(cap + UART_IIR); - - if (scratch & 0xC0) - hwconf->uart_type = PORT_16550A; - else - hwconf->uart_type = PORT_16450; - if (id == 1) - hwconf->ports = 8; - else - hwconf->ports = 4; - request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)"); - request_region(hwconf->vector, 1, "mxser(vector)"); - return hwconf->ports; -} - -#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ -#define CHIP_DO 0x02 /* Serial Data Output in Eprom */ -#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ -#define CHIP_DI 0x08 /* Serial Data Input in Eprom */ -#define EN_CCMD 0x000 /* Chip's command register */ -#define EN0_RSARLO 0x008 /* Remote start address reg 0 */ -#define EN0_RSARHI 0x009 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ -#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ -#define EN0_DCFG 0x00E /* Data configuration reg WR */ -#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ -#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ -#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ -static int mxser_read_register(int port, unsigned short *regs) -{ - int i, k, value, id; - unsigned int j; - - id = mxser_program_mode(port); - if (id < 0) - return id; - for (i = 0; i < 14; i++) { - k = (i & 0x3F) | 0x180; - for (j = 0x100; j > 0; j >>= 1) { - outb(CHIP_CS, port); - if (k & j) { - outb(CHIP_CS | CHIP_DO, port); - outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ - } else { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ - } - } - (void)inb(port); - value = 0; - for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); - if (inb(port) & CHIP_DI) - value |= j; - } - regs[i] = value; - outb(0, port); - } - mxser_normal_mode(port); - return id; -} - -static int mxser_program_mode(int port) -{ - int id, i, j, n; - /* unsigned long flags; */ - - spin_lock(&gm_lock); - outb(0, port); - outb(0, port); - outb(0, port); - (void)inb(port); - (void)inb(port); - outb(0, port); - (void)inb(port); - /* restore_flags(flags); */ - spin_unlock(&gm_lock); - - id = inb(port + 1) & 0x1F; - if ((id != C168_ASIC_ID) && - (id != C104_ASIC_ID) && - (id != C102_ASIC_ID) && - (id != CI132_ASIC_ID) && - (id != CI134_ASIC_ID) && - (id != CI104J_ASIC_ID)) - return -1; - for (i = 0, j = 0; i < 4; i++) { - n = inb(port + 2); - if (n == 'M') { - j = 1; - } else if ((j == 1) && (n == 1)) { - j = 2; - break; - } else - j = 0; - } - if (j != 2) - id = -2; - return id; -} - -static void mxser_normal_mode(int port) -{ - int i, n; - - outb(0xA5, port + 1); - outb(0x80, port + 3); - outb(12, port + 0); /* 9600 bps */ - outb(0, port + 1); - outb(0x03, port + 3); /* 8 data bits */ - outb(0x13, port + 4); /* loop back mode */ - for (i = 0; i < 16; i++) { - n = inb(port + 5); - if ((n & 0x61) == 0x60) - break; - if ((n & 1) == 1) - (void)inb(port); - } - outb(0x00, port + 4); -} - -module_init(mxser_module_init); -module_exit(mxser_module_exit); +/* + * mxser.c -- MOXA Smartio/Industio family multiport serial driver. + * + * Copyright (C) 1999-2001 Moxa Technologies (support@moxa.com.tw). + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Original release 10/26/00 + * + * 02/06/01 Support MOXA Industio family boards. + * 02/06/01 Support TIOCGICOUNT. + * 02/06/01 Fix the problem for connecting to serial mouse. + * 02/06/01 Fix the problem for H/W flow control. + * 02/06/01 Fix the compling warning when CONFIG_PCI + * don't be defined. + * 08/12/04 Add to supprt special baud rate + * 09/17/04 To support by pass flip, and directly send to ldisc + * 12/28/04 Add to support TIOCSBRK, TIOCCBRK ioctl. + * 12/31/04 Add TICOM_BRK, TICOM_PARITY & TIOCM_FRAME on TIOCMIWAIT input argument for Moxa + * private RealCOM used. + * 01/04/05 Add TICOM_XOFFHOLD and use buf_overrun to note xoff hold to support RealCOM. + * 02/04/05 Add to support for Q-Free specical used. + * 11/22/05 Porting to Moxa Embedded system. + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if 1 // add by Victor Yu. 02-21-2006 +#include +#endif + +#include +#include +#include +#include +#include + +#define VERSION_CODE(ver,rel,seq) ((ver << 16) | (rel << 8) | seq) + +#define MXSER_VERSION "2.0" +#define MXSERMAJOR 30 +#define MXSERCUMAJOR 35 + +#ifdef CONFIG_PCI +#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) +#include +#endif +#include +#endif /* ENABLE_PCI */ + +#include +#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2) +#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2) + +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006, to use embedded UART +#undef UART_RX +#undef UART_TX +#undef UART_DLL +#undef UART_TRG +#undef UART_DLM +#undef UART_IER +#undef UART_FCTR +#undef UART_IIR +#undef UART_FCR +#undef UART_EFR +#undef UART_LCR +#undef UART_MCR +#undef UART_LSR +#undef UART_MSR +#undef UART_SCR +#undef UART_EMSR +#define UART_RX 0 +#define UART_TX 0 +#define UART_DLL 0 +#define UART_TRG 0 +#define UART_DLM 4 +#define UART_IER 4 +#define UART_FCTR 4 +#define UART_IIR 8 +#define UART_FCR 8 +#define UART_EFR 8 +#define UART_LCR 12 +#define UART_MCR 16 +#define UART_LSR 20 +#define UART_MSR 24 +#define UART_SCR 28 +#define UART_EMSR 28 +#endif + +#define MXSER_EVENT_TXLOW 1 +#define MXSER_EVENT_HANGUP 2 + +#define SERIAL_DO_RESTART + +#define MXSER_BOARDS 4 /* Max. boards */ +#define MXSER_PORTS 32 /* Max. ports */ +#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board*/ +#define MXSER_ISR_PASS_LIMIT 256 // mask by Victor Yu. 02-04-2005 + +#define MXSER_ERR_IOADDR -1 +#define MXSER_ERR_IRQ -2 +#define MXSER_ERR_IRQ_CONFLIT -3 +#define MXSER_ERR_VECTOR -4 + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +#define WAKEUP_CHARS 256 + +#define UART_MCR_AFE 0x20 +#define UART_LSR_SPECIAL 0x1E + +#if 0 +#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) +#else +#define PORTNO(x) ((x)->index) +#endif + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +enum { + UC7110_BOARD=1, +}; + +static char *mxser_brdname[] = { + "MU860 UART", +}; + +/* FIXME */ +static int mxser_numports[] = { + 2, +}; + +typedef struct { + unsigned short vendor_id; + unsigned short device_id; + unsigned short board_type; +} mxser_pciinfo; + +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 +static mxser_pciinfo mxser_pcibrds[] = { + {0x1393,0x0001,UC7110_BOARD}, +}; +#endif + +/* + * MOXA ioctls + */ +#define MOXA 0x400 +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_CONF (MOXA + 35) +#define MOXA_DIAGNOSE (MOXA + 50) +#define MOXA_CHKPORTENABLE (MOXA + 60) +#define MOXA_HighSpeedOn (MOXA + 61) +#define MOXA_GET_MAJOR (MOXA + 63) +#define MOXA_GET_CUMAJOR (MOXA + 64) +#define MOXA_GETMSTATUS (MOXA + 65) + +// following add by Victor Yu. 01-05-2004 +#define MOXA_SET_OP_MODE (MOXA + 66) +#define MOXA_GET_OP_MODE (MOXA + 67) +#if 1 // add by Victor Yu. 05-02-2007, for GL ODM, I let it to be a Moxa standard feature +#define MOXA_BREAK_TIMER (MOXA+70) +#endif + +#if 1 // add by Victor Yu. 01-26-2005 +#define MOXA_UNWAIT (MOXA+200) +#define MXSER_PROC_NODE "driver/mxser" // add by Victor Yu. 07-27-2004 +#endif + +#define RS232_MODE 0 +#define RS485_2WIRE_MODE 1 +#define RS422_MODE 2 +#define RS485_4WIRE_MODE 3 +#define OP_MODE_MASK 3 +// above add by Victor Yu. 01-05-2004 + +#define CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 +#define MOXA_SET_SPECIAL_BAUD_RATE (MOXA+68) +#define MOXA_GET_SPECIAL_BAUD_RATE (MOXA+69) +#define NEW_MOXA_SET_SPECIAL_BAUD_RATE (MOXA+100) +#define NEW_MOXA_GET_SPECIAL_BAUD_RATE (MOXA+101) +#endif + +static int ttymajor=MXSERMAJOR; +static int calloutmajor=MXSERCUMAJOR; +static int verbose=0; + +/* Variables for insmod */ +MODULE_AUTHOR("Victor Yu."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MOXA MU860 UART Device Driver"); + +typedef struct _moxa_pci_info { + unsigned short busNum; + unsigned short devNum; + struct pci_dev *pdev; // add by Victor Yu. 06-23-2003 +} moxa_pci_info; + +struct mxser_hwconf { + int board_type; + int ports; + int irq; + int vector; + int vector_mask; + int uart_type; + int ioaddr[MXSER_PORTS_PER_BOARD]; + int baud_base[MXSER_PORTS_PER_BOARD]; + moxa_pci_info pciInfo; + int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002 + int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 01-05-2004 +}; + +struct mxser_struct { + int port; + int base; /* port base address */ + int irq; /* port using irq no. */ + int vector; /* port irq vector */ + int vectormask; /* port vector mask */ + int rx_trigger; /* Rx fifo trigger level */ + int baud_base; /* max. speed */ + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct * tty; + int read_status_mask; + int ignore_status_mask; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + unsigned long event; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ +#if 0 + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ +#endif + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct work_struct tqueue; + struct termios normal_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t delta_msr_wait; + struct async_icount icount; /* kernel counters for the 4 input interrupts */ + int timeout; + int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002 + int opmode_ioaddr; // add by Victor Yu. 01-05-2004 +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + int speed; +#endif +}; + +struct mxser_log { + int tick; + int rxcnt[MXSER_PORTS]; + int txcnt[MXSER_PORTS]; +}; + +struct mxser_mstatus{ + tcflag_t cflag; + int cts; + int dsr; + int ri; + int dcd; +}; + +static struct mxser_mstatus GMStatus[MXSER_PORTS]; + +static struct tty_driver mxvar_sdriver; +static struct mxser_struct mxvar_table[MXSER_PORTS]; +static struct termios * mxvar_termios[MXSER_PORTS+1]; +static struct termios * mxvar_termios_locked[MXSER_PORTS+1]; +static struct mxser_log mxvar_log; +static int mxvar_diagflag; +/* + * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need + * to lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char * mxvar_tmp_buf; +static struct semaphore mxvar_tmp_buf_sem; + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +#define B50_INDEX 1 // add by Victor Yu. 08-12-2004 +static int mxvar_baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 0 }; +#define BAUD_TABLE_NO (sizeof(mxvar_baud_table)/sizeof(int)) + +struct mxser_hwconf mxsercfg[MXSER_BOARDS]; + +/* + * static functions: + */ +#if 1 // add by Victor Yu. 02-21-2006 +static int mxser_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); // add by Victor Yu. 07-27-2004 +#endif +static void mxser_getcfg(int board,struct mxser_hwconf *hwconf); +int mxser_init(void); +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 +static int mxser_get_PCI_conf(int ,struct mxser_hwconf *); +#endif +static void mxser_do_softint(void *); +static int mxser_open(struct tty_struct *, struct file *); +static void mxser_close(struct tty_struct *, struct file *); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static int mxser_write(struct tty_struct *, const unsigned char *, int); +#else +static int mxser_write(struct tty_struct *, int, const unsigned char *, int); +#endif // LINUX_VERSION_CODE +static int mxser_write_room(struct tty_struct *); +static void mxser_flush_buffer(struct tty_struct *); +static int mxser_chars_in_buffer(struct tty_struct *); +static void mxser_flush_chars(struct tty_struct *); +static void mxser_put_char(struct tty_struct *, unsigned char); +static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); +static int mxser_ioctl_special(unsigned int, unsigned long); +static void mxser_throttle(struct tty_struct *); +static void mxser_unthrottle(struct tty_struct *); +static void mxser_set_termios(struct tty_struct *, struct termios *); +static void mxser_stop(struct tty_struct *); +static void mxser_start(struct tty_struct *); +static void mxser_hangup(struct tty_struct *); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static irqreturn_t mxser_interrupt(int, void *); +#else +static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); +#endif +static inline void mxser_receive_chars(struct mxser_struct *, int *); +static inline void mxser_transmit_chars(struct mxser_struct *); +static inline void mxser_check_modem_status(struct mxser_struct *, int); +static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); +static int mxser_startup(struct mxser_struct *); +static void mxser_shutdown(struct mxser_struct *); +static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios); +static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *); +static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *); +static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *); +static void mxser_send_break(struct mxser_struct *, int); +#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x +static int mxser_get_modem_info(struct mxser_struct *, unsigned int *); +static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *); +#endif +static void mxser_wait_until_sent(struct tty_struct *tty, int timeout); + +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x +static int mxser_tiocmget(struct tty_struct *tty, struct file *file); +static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +#endif +// +// follwoing is modified by Victor Yu. 08-15-2002 +// +// follow just for Moxa Must chip define. +// +// when LCR register (offset 0x03) write following value, +// the Must chip will enter enchance mode. And write value +// on EFR (offset 0x02) bit 6,7 to change bank. +#define MOXA_MUST_ENTER_ENCHANCE 0xBF + +// when enhance mode enable, access on general bank register +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_GDL_REGISTER 28 +#else +#define MOXA_MUST_GDL_REGISTER 7 +#endif + +#define MOXA_MUST_GDL_MASK 0x7F +#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80 + +#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO +// enchance register bank select and enchance mode setting register +// when LCR register equal to 0xBF +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_EFR_REGISTER 8 +#else +#define MOXA_MUST_EFR_REGISTER 2 +#endif + +// enchance mode enable +#define MOXA_MUST_EFR_EFRB_ENABLE 0x10 +// enchance reister bank set 0, 1, 2 +#define MOXA_MUST_EFR_BANK0 0x00 +#define MOXA_MUST_EFR_BANK1 0x40 +#define MOXA_MUST_EFR_BANK2 0x80 +#define MOXA_MUST_EFR_BANK3 0xC0 +#define MOXA_MUST_EFR_BANK_MASK 0xC0 + +// set XON1 value register, when LCR=0xBF and change to bank0 +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_XON1_REGISTER 16 +#else +#define MOXA_MUST_XON1_REGISTER 4 +#endif + +// set XON2 value register, when LCR=0xBF and change to bank0 +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_XON2_REGISTER 20 +#else +#define MOXA_MUST_XON2_REGISTER 5 +#endif + +// set XOFF1 value register, when LCR=0xBF and change to bank0 +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_XOFF1_REGISTER 24 +#else +#define MOXA_MUST_XOFF1_REGISTER 6 +#endif + +// set XOFF2 value register, when LCR=0xBF and change to bank0 +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +#define MOXA_MUST_XOFF2_REGISTER 28 +#define MOXA_MUST_RBRTL_REGISTER 16 +#define MOXA_MUST_RBRTH_REGISTER 20 +#define MOXA_MUST_RBRTI_REGISTER 24 +#define MOXA_MUST_THRTL_REGISTER 28 +#define MOXA_MUST_ENUM_REGISTER 16 +#define MOXA_MUST_HWID_REGISTER 20 +#define MOXA_MUST_ECR_REGISTER 24 +#define MOXA_MUST_CSR_REGISTER 28 +#else +#define MOXA_MUST_XOFF2_REGISTER 7 +#define MOXA_MUST_RBRTL_REGISTER 4 +#define MOXA_MUST_RBRTH_REGISTER 5 +#define MOXA_MUST_RBRTI_REGISTER 6 +#define MOXA_MUST_THRTL_REGISTER 7 +#define MOXA_MUST_ENUM_REGISTER 4 +#define MOXA_MUST_HWID_REGISTER 5 +#define MOXA_MUST_ECR_REGISTER 6 +#define MOXA_MUST_CSR_REGISTER 7 +#endif + +// good data mode enable +#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 +// only good data put into RxFIFO +#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 + +// enable CTS interrupt +#define MOXA_MUST_IER_ECTSI 0x80 +// eanble RTS interrupt +#define MOXA_MUST_IER_ERTSI 0x40 +// enable Xon/Xoff interrupt +#define MOXA_MUST_IER_XINT 0x20 +// enable GDA interrupt +#define MOXA_MUST_IER_EGDAI 0x10 + +#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI) + +// GDA interrupt pending +#define MOXA_MUST_IIR_GDA 0x1C +#define MOXA_MUST_IIR_RDA 0x04 +#define MOXA_MUST_IIR_RTO 0x0C +#define MOXA_MUST_IIR_LSR 0x06 + +// recieved Xon/Xoff or specical interrupt pending +#define MOXA_MUST_IIR_XSC 0x10 + +// RTS/CTS change state interrupt pending +#define MOXA_MUST_IIR_RTSCTS 0x20 +#define MOXA_MUST_IIR_MASK 0x3E + +#define MOXA_MUST_MCR_XON_FLAG 0x40 +#define MOXA_MUST_MCR_XON_ANY 0x80 +#define MOXA_MUST_HARDWARE_ID 0x01 +#define MOXA_MUST_HARDWARE_ID1 0x02 + +// software flow control on chip mask value +#define MOXA_MUST_EFR_SF_MASK 0x0F +// send Xon1/Xoff1 +#define MOXA_MUST_EFR_SF_TX1 0x08 +// send Xon2/Xoff2 +#define MOXA_MUST_EFR_SF_TX2 0x04 +// send Xon1,Xon2/Xoff1,Xoff2 +#define MOXA_MUST_EFR_SF_TX12 0x0C +// don't send Xon/Xoff +#define MOXA_MUST_EFR_SF_TX_NO 0x00 +// Tx software flow control mask +#define MOXA_MUST_EFR_SF_TX_MASK 0x0C +// don't receive Xon/Xoff +#define MOXA_MUST_EFR_SF_RX_NO 0x00 +// receive Xon1/Xoff1 +#define MOXA_MUST_EFR_SF_RX1 0x02 +// receive Xon2/Xoff2 +#define MOXA_MUST_EFR_SF_RX2 0x01 +// receive Xon1,Xon2/Xoff1,Xoff2 +#define MOXA_MUST_EFR_SF_RX12 0x03 +// Rx software flow control mask +#define MOXA_MUST_EFR_SF_RX_MASK 0x03 + +#define MOXA_MUST_MIN_XOFFLIMIT 66 +#define MOXA_MUST_MIN_XONLIMIT 20 + +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif + +#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \ + if ( (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \ + (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \ + (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \ + } \ +} + +#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define MOXA_MUST_RBRL_VALUE 4 +#define SET_MOXA_MUST_FIFO_VALUE(info) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((info)->base+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (info)->base+UART_LCR); \ + __efr = inb((info)->base+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ + outb(__efr, (info)->base+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)0, (info)->base+MOXA_MUST_THRTL_REGISTER); \ + outb((UCHAR)((info)->rx_trigger), (info)->base+MOXA_MUST_RBRTH_REGISTER); \ + if ( (info)->rx_trigger <= MOXA_MUST_RBRL_VALUE ) { \ + outb((UCHAR)0, (info)->base+MOXA_MUST_RBRTI_REGISTER); \ + outb((UCHAR)0, (info)->base+MOXA_MUST_RBRTL_REGISTER); \ + } else { \ + outb((UCHAR)((info)->rx_trigger-MOXA_MUST_RBRL_VALUE), \ + (info)->base+MOXA_MUST_RBRTI_REGISTER); \ + outb((UCHAR)((info)->rx_trigger-MOXA_MUST_RBRL_VALUE), \ + (info)->base+MOXA_MUST_RBRTL_REGISTER); \ + } \ + outb(__oldlcr, (info)->base+UART_LCR); \ +} + +#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK2; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb((UCHAR)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK2; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_MASK; \ + __efr |= MOXA_MUST_EFR_SF_TX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ + __efr |= MOXA_MUST_EFR_SF_TX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_MASK; \ + __efr |= MOXA_MUST_EFR_SF_RX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ + __efr |= MOXA_MUST_EFR_SF_RX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ + UCHAR __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_MASK; \ + __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} + +#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \ + UCHAR __oldmcr; \ + __oldmcr = inb((baseio)+UART_MCR); \ + __oldmcr |= MOXA_MUST_MCR_XON_ANY; \ + outb(__oldmcr, (baseio)+UART_MCR); \ +} + +#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \ + UCHAR __oldmcr; \ + __oldmcr = inb((baseio)+UART_MCR); \ + __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \ + outb(__oldmcr, (baseio)+UART_MCR); \ +} + +#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER) + +#if 1 // add by Victor Yu. 02-21-2006 +static int mxser_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len=0, board, port, p, i, j; + struct mxser_struct *info; + + for ( board=0, port=0; boardcount ) { // has opened +#if 0 // mask by Victor Yu. 02-21-2006 +#ifndef B921600 +#define B921600 (B460800 +1) +#endif + switch( info->tty->termios->c_cflag & (CBAUD | CBAUDEX) ){ +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE + case B40000000 : + len += sprintf(page+len, " %d 1", info->speed); + goto read_proc_l1; + break; +#endif + case B921600 : j = 20; break; + case B460800 : j = 19; break; + case B230400 : j = 18; break; + case B115200 : j = 17; break; + case B57600 : j = 16; break; + case B38400 : j = 15; break; + case B19200 : j = 14; break; + case B9600 : j = 13; break; + case B4800 : j = 12; break; + case B2400 : j = 11; break; + case B1800 : j = 10; break; + case B1200 : j = 9; break; + case B600 : j = 8; break; + case B300 : j = 7; break; + case B200 : j = 6; break; + case B150 : j = 5; break; + case B134 : j = 4; break; + case B110 : j = 3; break; + case B75 : j = 2; break; + case B50 : j = 1; break; + default: j = 0; break; + } + + if ( j == 15 ) { + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI ) + j = 16; /* 57600 bps */ + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) + j = 17; /* 115200 bps */ +#ifdef ASYNC_SPD_SHI + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + j = 18; +#endif +#ifdef ASYNC_SPD_WARP + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + j = 19; +#endif + } + len += sprintf(page+len, " %d 1", mxvar_baud_table[j]); +#else + len += sprintf(page+len, " %d 1", info->speed); +#endif + } else { // not opened +#if 0 // mask by Victor Yu. 02-21-2006 + len += sprintf(page+len, " 9600 2"); +#else + len += sprintf(page+len, " %d 2", info->speed); +#endif + } + + // output interface (1-other, 2-rs232, 3-rs422, 4-rs423, 5-v35) +#if 0 // mask by Victor Yu. 02-21-2006 +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE +read_proc_l1: +#endif + switch ( info->interface ) { + case RS232_MODE : + len += sprintf(page+len, " 2"); + break; + case RS422_MODE : + len += sprintf(page+len, " 3"); + break; + default : + len += sprintf(page+len, " 1"); + break; + } +#else + { + int opmode; + int shiftbit; +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006 + shiftbit = ((info->port%4)+2) * 2; + opmode = inl(info->opmode_ioaddr) >> shiftbit; +#else + shiftbit = (info->port%4) * 2; + opmode = inb(info->opmode_ioaddr) >> shiftbit; +#endif + opmode &= OP_MODE_MASK; + switch ( opmode ) { + case RS232_MODE : + len += sprintf(page+len, " 2"); + break; + case RS422_MODE : + len += sprintf(page+len, " 3"); + break; + default : + len += sprintf(page+len, " 1"); + break; + } + } +#endif + + // output data bits + if ( info->count ) { // has opened + switch ( info->tty->termios->c_cflag & CSIZE ) { + case CS5 : + len += sprintf(page+len, " 5"); + break; + case CS6 : + len += sprintf(page+len, " 6"); + break; + case CS7 : + len += sprintf(page+len, " 7"); + break; + case CS8 : + default : + len += sprintf(page+len, " 8"); + break; + } + } else { // not opened + len += sprintf(page+len, " 8"); + } + + // output stop bits (1-one, 2-two, 3-one-and-half, 4-dynamic) + if ( info->count ) { // has opened + if ( info->tty->termios->c_cflag & CSTOPB ) { + len += sprintf(page+len, " 2"); + } else { + len += sprintf(page+len, " 1"); + } + } else { + len += sprintf(page+len, " 1"); + } + + // output parity (1-none, 2-odd, 3-even, 4-mark, 5-space) + if ( info->count ) { // has opened + if ( info->tty->termios->c_cflag & PARENB ) { + if ( info->tty->termios->c_cflag & PARODD ) { + len += sprintf(page+len, " 2"); + } else { + len += sprintf(page+len, " 3"); + } + } else { + len += sprintf(page+len, " 1"); + } + } else { // not opened + len += sprintf(page+len, " 1"); + } + + // output CTS DSR DCD status (1-none, 2-on, 3-off) + j = inb(info->base+UART_MSR); + if ( j & UART_MSR_CTS ) + len += sprintf(page+len, " 2"); + else + len += sprintf(page+len, " 3"); + if ( j & UART_MSR_DSR ) + len += sprintf(page+len, " 2"); + else + len += sprintf(page+len, " 3"); + if ( j & UART_MSR_DCD ) + len += sprintf(page+len, " 2"); + else + len += sprintf(page+len, " 3"); + + // output RTS DTR status (1-none, 2-on, 3-off) + j = inb(info->base+UART_MCR); + if ( j & UART_MCR_RTS ) + len += sprintf(page+len, " 2"); + else + len += sprintf(page+len, " 3"); + if ( j & UART_MCR_DTR ) + len += sprintf(page+len, " 2"); + else + len += sprintf(page+len, " 3"); + + // end output + len += sprintf(page+len, "\n"); + } + } + +end_mxser_read_proc: + if ( len <= (off + count) ) + *eof = 1; + *start = page + off; + len -= off; + if ( len > count ) + len = count; + if ( len < 0 ) + len = 0; + + return len; +} +#endif + +/* + * The MOXA Smartio/Industio serial driver boot-time initialization code! + */ +static int __init mxser_init_module(void) +{ + int ret; + + if (verbose) + printk("Loading module mxser ...\n"); + ret = mxser_init(); + if (verbose) + printk("Done.\n"); + return (ret); +} + +static void __exit mxser_exit_module(void) +{ + int i,err = 0; + + + if (verbose) + printk("Unloading module mxser ...\n"); +#if 1 // mask by Victor Yu. 11-22-2005 + if ((err |= tty_unregister_driver(&mxvar_sdriver))) + printk("Couldn't unregister MOXA Smartio/Industio family serial driver\n"); +#else // add by Victor Yu. 11-22-2005 + put_tty_driver(&mxvar_sdriver); +#endif // 11-22-2005 + + for(i=0; iports; i++, n++, info++ ) { + if (verbose) { + printk(" ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]); + if ( hwconf->baud_base[i] == 115200 ) + printk(" max. baud rate up to 115200 bps.\n"); + else + printk(" max. baud rate up to 921600 bps.\n"); + } + info->port = n; + info->base = hwconf->ioaddr[i]; + info->irq = hwconf->irq; + info->vector = hwconf->vector; + info->vectormask = hwconf->vector_mask; + info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004 + + // following add by Victor Yu. 08-30-2002 + // Moxa Must UART support FIFO is 64bytes for Tx/Rx + // but receive FIFO just can set up to 62 will be OK. + info->rx_trigger = 120; + info->baud_base = hwconf->baud_base[i]; + info->flags = ASYNC_SHARE_IRQ; + info->type = hwconf->uart_type; + + // following add by Victor Yu. 08-30-2002 + info->xmit_fifo_size = 128; + ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base); + info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i]; + // above add by Victor Yu. 08-30-2002 + + info->custom_divisor = hwconf->baud_base[i] * 16; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + INIT_WORK(&info->tqueue, mxser_do_softint, info); + info->normal_termios = mxvar_sdriver.init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->icount.rx = info->icount.tx = 0; + info->icount.cts = info->icount.dsr = + info->icount.dsr = info->icount.dcd = 0; + info->icount.frame = info->icount.overrun = + info->icount.brk = info->icount.parity = 0; + info->icount.buf_overrun = 0; +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add b Victor Yu. 08-12-2004 + info->speed = 9600; +#endif + } + +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 + request_region(hwconf->ioaddr[0],8*hwconf->ports,"mxser(io)"); + if ((hwconf->pciInfo.busNum == 0)&&(hwconf->pciInfo.devNum == 0)) + request_region(hwconf->vector,1,"mxser(vector)"); + else + request_region(hwconf->vector,16,"mxser(vector)"); +#endif + + /* + * Allocate the IRQ if necessary + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_COODE + + n = board*MXSER_PORTS_PER_BOARD; + info = &mxvar_table[n]; + + retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), + "mxser", info); + if ( retval ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + printk("Board %d: %s", board, mxser_brdname[hwconf->board_type-1]); + printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n",info->irq); + return(retval); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + + return 0; +} + +static void mxser_getcfg(int board,struct mxser_hwconf *hwconf) +{ + mxsercfg[board] = *hwconf; +} + +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 +static int mxser_get_PCI_conf(int board_type,struct mxser_hwconf *hwconf) +{ + int i; + unsigned int ioaddress; + struct pci_dev *pdev=hwconf->pciInfo.pdev; + + hwconf->board_type = board_type; + hwconf->ports = mxser_numports[board_type-1]; + ioaddress = pci_resource_start(pdev, 2); + request_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2), + "mxser(IO)"); + for (i = 0; i < hwconf->ports; i++) { + hwconf->ioaddr[i] = ioaddress + 8*i; + + // disable the interrupt + outb(0, hwconf->ioaddr[i]+1); + // flush FIFO + outb(0x06, hwconf->ioaddr[i]+2); + // flush interrupt + inb(hwconf->ioaddr[i]+2); + inb(hwconf->ioaddr[i]+6); + inb(hwconf->ioaddr[i]+5); + inb(hwconf->ioaddr[i]); + hwconf->MaxCanSetBaudRate[i] = 921600; + } + + ioaddress = pci_resource_start(pdev, 3); + request_region(pci_resource_start(pdev, 3), + pci_resource_len(pdev, 3), + "mxser(vector)"); + hwconf->vector = ioaddress; + + // following add by Victor Yu. 01-05-2004 + for (i = 0; i < hwconf->ports; i++) { + if ( i < 4 ) + hwconf->opmode_ioaddr[i] = ioaddress + 4; + else + hwconf->opmode_ioaddr[i] = ioaddress + 0x0c; + } + outb(0, ioaddress+4); // default set to RS232 mode + outb(0, ioaddress+0x0c); //default set to RS232 mode + // above add by Victor Yu. 01-05-2004 + + hwconf->irq = hwconf->pciInfo.pdev->irq; + + hwconf->uart_type = PORT_16550A; + hwconf->vector_mask = 0; + for (i = 0; i < hwconf->ports; i++) { + hwconf->vector_mask |= (1<baud_base[i] = 921600; + } + return(0); +} +#endif + +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 +static void ia240_hw_set(struct mxser_hwconf *hwconf) +{ + int i; + + hwconf->board_type = UC7110_BOARD; + /* FIXME */ + hwconf->ports = 2; + hwconf->vector_mask = 0x0c; + hwconf->irq = IRQ_UART; + hwconf->vector = CPE_UART_INT_VEC_VA_BASE; + hwconf->uart_type = PORT_16550A; + for ( i=0; iports; i++ ) { + hwconf->ioaddr[i] = CPE_UART3_VA_BASE + i * 32; + hwconf->baud_base[i] = 921600; + hwconf->MaxCanSetBaudRate[i] = 921600; + hwconf->opmode_ioaddr[i] = CPE_UART_MODE_VA_BASE; + } +} +#endif + +int mxser_init(void) +{ + int i, m; + int ret1, ret2; +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 + struct pci_dev *pdev=NULL; + int n, index, retval, b; +#endif + struct mxser_hwconf hwconf; + + printk("MOXA MU860 UART Device Driver version %s\n",MXSER_VERSION); + + /* Initialize the tty_driver structure */ + memset(&mxvar_sdriver, 0, sizeof(struct tty_driver)); + mxvar_sdriver.magic = TTY_DRIVER_MAGIC; + mxvar_sdriver.name = "ttyM"; + mxvar_sdriver.major = ttymajor; + mxvar_sdriver.minor_start = 0; + mxvar_sdriver.num = MXSER_PORTS + 1; + mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL; + mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL; + mxvar_sdriver.init_termios = tty_std_termios; + mxvar_sdriver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; + mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW; + mxvar_sdriver.refcount = 0; + mxvar_sdriver.termios = mxvar_termios; + mxvar_sdriver.termios_locked = mxvar_termios_locked; + + mxvar_sdriver.open = mxser_open; + mxvar_sdriver.close = mxser_close; + mxvar_sdriver.write = mxser_write; + mxvar_sdriver.put_char = mxser_put_char; + mxvar_sdriver.flush_chars = mxser_flush_chars; + mxvar_sdriver.write_room = mxser_write_room; + mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer; + mxvar_sdriver.flush_buffer = mxser_flush_buffer; + mxvar_sdriver.ioctl = mxser_ioctl; + mxvar_sdriver.throttle = mxser_throttle; + mxvar_sdriver.unthrottle = mxser_unthrottle; + mxvar_sdriver.set_termios = mxser_set_termios; + mxvar_sdriver.stop = mxser_stop; + mxvar_sdriver.start = mxser_start; + mxvar_sdriver.hangup = mxser_hangup; + mxvar_sdriver.wait_until_sent = mxser_wait_until_sent; +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x + mxvar_sdriver.tiocmget = mxser_tiocmget; + mxvar_sdriver.tiocmset = mxser_tiocmset; +#endif + + printk("Tty devices major number = %d\n",ttymajor); + + mxvar_diagflag = 0; + memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); + memset(&mxvar_log, 0, sizeof(struct mxser_log)); + + m = 0; +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006 + ia240_hw_set(&hwconf); + if ( mxser_initbrd(m,&hwconf) < 0 ) + return -1; + mxser_getcfg(m,&hwconf); + m++; +#else + { + n = sizeof (mxser_pcibrds)/sizeof (mxser_pciinfo); + index = 0; + b = 0; + while (b < n) { + pdev = pci_find_device(mxser_pcibrds[b].vendor_id, + mxser_pcibrds[b].device_id, + pdev); + if ( pdev == NULL ) { + b++; + continue; + } + hwconf.pciInfo.busNum = pdev->bus->number; + hwconf.pciInfo.devNum = pdev->devfn; + hwconf.pciInfo.pdev = pdev; + printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",mxser_brdname[mxser_pcibrds[b].board_type-1],pdev->bus->number,pdev->devfn >> 3); + if ( m >= MXSER_BOARDS) { + printk("Too many Smartio/Industio family boards find (maximum %d),board not configured\n",MXSER_BOARDS); + } + else { + if ( pci_enable_device(pdev) ) { + printk("Moxa SmartI/O PCI enable fail !\n"); + continue; + } + retval = mxser_get_PCI_conf(mxser_pcibrds[b].board_type,&hwconf); + if (retval < 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + continue; + + } + + if(mxser_initbrd(m,&hwconf)<0) + continue; + mxser_getcfg(m,&hwconf); + m++; + } + } + } +#endif + + for(i=m; itty; + + if (tty) { + if ( test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event) ) { + if ( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup ) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + if ( test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event) ) { + tty_hangup(tty); + } + } + //MOD_DEC_USE_COUNT; +} + +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x +static int mxser_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; + unsigned char control, status; + int result; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + control = info->MCR; + status = inb(info->base + UART_MSR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | + ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | + ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | + ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | + ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | + ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + return(result); +} + +static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) +{ + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( set & TIOCM_RTS ) + info->MCR |= UART_MCR_RTS; + if ( set & TIOCM_DTR ) + info->MCR |= UART_MCR_DTR; + if ( clear & TIOCM_RTS ) + info->MCR &= ~UART_MCR_RTS; + if ( clear & TIOCM_DTR ) + info->MCR &= ~UART_MCR_DTR; + outb(info->MCR, info->base + UART_MCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(0); +} +#endif +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int mxser_open(struct tty_struct * tty, struct file * filp) +{ + struct mxser_struct * info; + int retval, line; + unsigned long page; +#if 1 // add by Victor Yu. 12-28-2004 + unsigned long flags; +#endif + + line = PORTNO(tty); + if ( line == MXSER_PORTS ) + return(0); + if ( (line < 0) || (line > MXSER_PORTS) ) + return(-ENODEV); + + info = mxvar_table + line; + if ( !info->base ) + return(-ENODEV); + + tty->driver_data = info; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->tty = tty; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + + if ( !mxvar_tmp_buf ) { + page = get_zeroed_page(GFP_KERNEL); + if ( !page ) + return(-ENOMEM); + if ( mxvar_tmp_buf ) + free_page(page); + else + mxvar_tmp_buf = (unsigned char *)page; + } + + /* + * Start up serial port + */ + retval = mxser_startup(info); + if ( retval ) + return(retval); + + retval = mxser_block_til_ready(tty, filp, info); + if ( retval ) + return(retval); + +#if 0 // mask by Victor Yu. 12-28-2004 + info->count++; +#else // add by Victor Yu. 12-28-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->count++; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + //MOD_INC_USE_COUNT; + + if ( (info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS) ) { + *tty->termios = info->normal_termios; + mxser_change_speed(info, 0); + } + +#if 0 // mask by Victor Yu. 02-08-2007 + save_flags(flags); + cli(); + clear_bit(TTY_DONT_FLIP, &tty->flags); + restore_flags(flags); +#endif + +/* unmark here for very high baud rate (ex. 921600 bps) used +*/ +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) + tty->low_latency = 1; +#endif + return(0); +} + +/* + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + */ +static void mxser_close(struct tty_struct * tty, struct file * filp) +{ + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + unsigned long timeout; + + if ( PORTNO(tty) == MXSER_PORTS ) + return; + if ( !info ) + return; + + if ( tty_hung_up_p(filp) ) { + //MOD_DEC_USE_COUNT; + return; + } + +#if 1 // add by Victor Yu. 12-28-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + if ( (tty->count == 1) && (info->count != 1) ) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("mxser_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if ( --info->count < 0 ) { + printk("mxser_close: bad serial port count for ttyM%d: %d\n", + info->port, info->count); + info->count = 0; + } + if ( info->count ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + //MOD_DEC_USE_COUNT; + return; + } + info->flags |= ASYNC_CLOSING; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); // add by Victor Yu. 09-26-2002 +#endif // LINUX_VERSION_CODE + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if ( info->flags & ASYNC_NORMAL_ACTIVE ) + info->normal_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if ( info->closing_wait != ASYNC_CLOSING_WAIT_NONE ) { + tty_wait_until_sent(tty, info->closing_wait); + } + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~(UART_IER_RLSI|MOXA_MUST_RECV_ISR); + if ( info->flags & ASYNC_INITIALIZED ) { + outb(info->IER, info->base + UART_IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + timeout = jiffies + HZ; + while ( !(inb(info->base + UART_LSR) & UART_LSR_TEMT) ) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(5); + if ( time_after(jiffies, timeout) ) + break; + } + } + mxser_shutdown(info); + + if ( tty->driver->flush_buffer ) + tty->driver->flush_buffer(tty); + if ( tty->ldisc.flush_buffer ) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if ( info->blocked_open ) { + if ( info->close_delay ) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + + info->flags &= ~(ASYNC_NORMAL_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + + //MOD_DEC_USE_COUNT; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static int mxser_write(struct tty_struct * tty, const unsigned char * buf, int count) +#else +static int mxser_write(struct tty_struct * tty, int from_user, const unsigned char * buf, int count) +#endif // LINUX_VERSION_CODE +{ + int c, total = 0; + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + + if ( !tty || !info->xmit_buf || !mxvar_tmp_buf ) + return(0); + +#if 0 // mask by Victor Yu. 10-13-2004 + if ( from_user ) + down(&mxvar_tmp_buf_sem); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + while ( 1 ) { +// cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if ( c <= 0 ) + break; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 + if ( from_user ) { + /* + copy_from_user(mxvar_tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); + */ + copy_from_user(info->xmit_buf+info->xmit_head, buf, c); + } else +#endif // LINUX_VERSION_CODE + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt += c; +// restore_flags(flags); + buf += c; + count -= c; + total += c; + } +#if 0 // mask by Victor Yu. 10-13-2004 + if ( from_user ) + up(&mxvar_tmp_buf_sem); +#endif + if ( info->xmit_cnt && !tty->stopped && + !(info->IER & UART_IER_THRI) ) { + if (!tty->hw_stopped||(info->type == PORT_16550A)) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(total); +} + +static void mxser_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + + if ( !tty || !info->xmit_buf ) + return; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( info->xmit_cnt >= SERIAL_XMIT_SIZE - 1 ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE - 1; + info->xmit_cnt++; + if ( !tty->stopped && !(info->IER & UART_IER_THRI) ) { + if (!tty->hw_stopped||(info->type == PORT_16550A)) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +static void mxser_flush_chars(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + + if ( info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || + (tty->hw_stopped && info->type!=PORT_16550A)) + return; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +static int mxser_write_room(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + int ret; + + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if ( ret < 0 ) + ret = 0; + return(ret); +} + +static int mxser_chars_in_buffer(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + + return(info->xmit_cnt); +} + +static void mxser_flush_buffer(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + wake_up_interruptible(&tty->write_wait); + if ( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup ) + (tty->ldisc.write_wakeup)(tty); +} + +static int mxser_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + int error; +#endif + unsigned long flags; + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; + int retval; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long templ; + if ( PORTNO(tty) == MXSER_PORTS ) + return(mxser_ioctl_special(cmd, arg)); + + // following add by Victor Yu. 01-05-2004 + if ( cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE ) { + int opmode, p; + int shiftbit; + unsigned int val; + + p = info->port % 4; + if ( cmd == MOXA_SET_OP_MODE ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + get_from_user(opmode,(int *)arg); + if ( opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE ) + return -EFAULT; +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006 + shiftbit = (p+2) * 2; + val = inl(info->opmode_ioaddr); +#else + shiftbit = p * 2; + val = inb(info->opmode_ioaddr); +#endif + val &= (~(3 << shiftbit)); + val |= (opmode << shiftbit); +#ifdef CONFIG_ARCH_MOXART + outl(val, info->opmode_ioaddr); +#else + outb(val, info->opmode_ioaddr); +#endif + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006 + shiftbit = (p+2) * 2; + opmode = inl(info->opmode_ioaddr) >> shiftbit; +#else + shiftbit = p * 2; + opmode = inb(info->opmode_ioaddr) >> shiftbit; +#endif + opmode &= OP_MODE_MASK; + copy_to_user((int*)arg, &opmode, sizeof(int)); + } + return 0; + } + // above add by Victor Yu. 01-05-2004 + +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 +#if 0 // 02-16-2007, mask by Victor Yu. To support Moxa Group define about this + if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE || cmd == MOXA_GET_SPECIAL_BAUD_RATE ) { +#else + if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE || cmd == MOXA_GET_SPECIAL_BAUD_RATE || + cmd == NEW_MOXA_SET_SPECIAL_BAUD_RATE || cmd == NEW_MOXA_GET_SPECIAL_BAUD_RATE ) { +#endif + int speed, i; +#if 0 // 02-16-2007, mask by Victor Yu. To support Moxa Group define about this + if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE ) { +#else + if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE || + cmd == MOXA_SET_SPECIAL_BAUD_RATE ) { +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + get_from_user(speed,(int *)arg); + if ( speed <= 0 || speed > info->MaxCanSetBaudRate ) + return -EFAULT; + if ( !info->tty || !info->tty->termios || !info->base ) + return 0; + info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX); + for ( i=0; itty->termios->c_cflag |= B4000000; + } else { + switch ( mxvar_baud_table[i] ) { + case 921600 : info->tty->termios->c_cflag |= B921600; break; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 + case 576000 : info->tty->termios->c_cflag |= B576000; break; + case 500000 : info->tty->termios->c_cflag |= B500000; break; +#endif + case 460800 : info->tty->termios->c_cflag |= B460800; break; + case 230400 : info->tty->termios->c_cflag |= B230400; break; + case 115200 : info->tty->termios->c_cflag |= B115200; break; + case 57600 : info->tty->termios->c_cflag |= B57600; break; + case 38400 : info->tty->termios->c_cflag |= B38400; break; + case 19200 : info->tty->termios->c_cflag |= B19200; break; + case 9600 : info->tty->termios->c_cflag |= B9600; break; + case 4800 : info->tty->termios->c_cflag |= B4800; break; + case 2400 : info->tty->termios->c_cflag |= B2400; break; + case 1800 : info->tty->termios->c_cflag |= B1800; break; + case 1200 : info->tty->termios->c_cflag |= B1200; break; + case 600 : info->tty->termios->c_cflag |= B600; break; + case 300 : info->tty->termios->c_cflag |= B300; break; + case 200 : info->tty->termios->c_cflag |= B200; break; + case 150 : info->tty->termios->c_cflag |= B150; break; + case 134 : info->tty->termios->c_cflag |= B134; break; + case 110 : info->tty->termios->c_cflag |= B110; break; + case 75 : info->tty->termios->c_cflag |= B75; break; + case 50 : info->tty->termios->c_cflag |= B50; break; + } + } + info->speed = speed; + mxser_change_speed(info, 0); + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + copy_to_user((int*)arg, &info->speed, sizeof(int)); + } + return 0; + } +#endif + + if ( (cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && + (cmd != TIOCGICOUNT) ) { + if ( tty->flags & (1 << TTY_IO_ERROR) ) + return(-EIO); + } + switch ( cmd ) { +#if 1 // add by Victor Yu. 05-02-2007, for GL ODM, I let it to be Moxa standard feature + case MOXA_BREAK_TIMER : + retval = tty_check_change(tty); + if ( retval ) + return(retval); + tty_wait_until_sent(tty, 0); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR); + udelay(arg); + outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + break; +#endif +#if 1 // add by Victor Yu. 12-28-2004 + case TIOCSBRK : // start to send break + retval = tty_check_change(tty); + if ( retval ) + return(retval); + tty_wait_until_sent(tty, 0); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return 0; + case TIOCCBRK : // stop to send break +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return 0; +#endif + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if ( retval ) + return(retval); + tty_wait_until_sent(tty, 0); + if ( !arg ) + mxser_send_break(info, HZ/4); /* 1/4 second */ + return(0); + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if ( retval ) + return(retval); + tty_wait_until_sent(tty, 0); + mxser_send_break(info, arg ? arg*(HZ/10) : HZ/4); + return(0); + case TIOCGSOFTCAR: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + put_to_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); + return 0; + case TIOCSSOFTCAR: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + get_from_user(templ,(unsigned long *)arg); + arg = templ; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return(0); +#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x + case TIOCMGET: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(unsigned int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + return(mxser_get_modem_info(info, (unsigned int *)arg)); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return(mxser_set_modem_info(info, cmd, (unsigned int *)arg)); +#endif + case TIOCGSERIAL: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct serial_struct)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + return(mxser_get_serial_info(info, (struct serial_struct *)arg)); + case TIOCSSERIAL: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_READ, (void *)arg, + sizeof(struct serial_struct)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + return(mxser_set_serial_info(info, (struct serial_struct *)arg)); + case TIOCSERGETLSR: /* Get line status register */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. + error = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(unsigned int)); + if ( error ) + return(error); + else +#endif // LINUX_VERSION_CODE + return(mxser_get_lsr_info(info, (unsigned int *)arg)); + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + cprev = info->icount; /* note the counters on entry */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + while ( 1 ) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if ( signal_pending(current) ) { + return(-ERESTARTSYS); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + cnow = info->icount; /* atomic copy */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#if 0 // mask by Victor Yu. 12-31-2004 + if ( cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts ) + return(-EIO); /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return(0); + } +#else // add by Victor Yu. 12-31-2004 +#define TIOCM_BRK 0x10000 +#define TIOCM_PARITY 0x20000 +#define TIOCM_FRAME 0x40000 +#define TIOCM_XOFFHOLD 0x80000 + if ( cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts && + cnow.brk == cprev.brk && cnow.parity == cprev.parity && + cnow.frame == cprev.frame && cnow.buf_overrun == cprev.buf_overrun ) + return(-EIO); /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) || + ((arg & TIOCM_BRK) && (cnow.brk != cprev.brk)) || + ((arg & TIOCM_PARITY) && (cnow.parity != cprev.parity)) || + ((arg & TIOCM_FRAME) && (cnow.frame != cprev.frame)) || + ((arg & TIOCM_XOFFHOLD) && (cnow.buf_overrun != cprev.buf_overrun)) ) { + return(0); + } +#endif + cprev = cnow; + } + /* NOTREACHED */ + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + +#if 1 // add by Victor Yu. 01-26-2005 + case MOXA_UNWAIT : + wake_up_interruptible(&info->delta_msr_wait); + break; +#endif + + case TIOCGICOUNT: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct serial_icounter_struct)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + cnow = info->icount; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + p_cuser = (struct serial_icounter_struct *)arg; +/* modified by casper 1/11/2000 */ +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) + if (put_user(cnow.frame, &p_cuser->frame)) + return -EFAULT; + if (put_user(cnow.brk, &p_cuser->brk)) + return -EFAULT; + if (put_user(cnow.overrun, &p_cuser->overrun)) + return -EFAULT; + if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) + return -EFAULT; + if (put_user(cnow.parity, &p_cuser->parity)) + return -EFAULT; + if (put_user(cnow.rx, &p_cuser->rx)) + return -EFAULT; + if (put_user(cnow.tx, &p_cuser->tx)) + return -EFAULT; +#endif + + put_to_user(cnow.cts, &p_cuser->cts); + put_to_user(cnow.dsr, &p_cuser->dsr); + put_to_user(cnow.rng, &p_cuser->rng); + put_to_user(cnow.dcd, &p_cuser->dcd); + +/* */ + return(0); + case MOXA_HighSpeedOn: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + put_to_user(info->baud_base != 115200 ? 1 : 0, (int *)arg); + return(0); + default: + return(-ENOIOCTLCMD); + } + return(0); +} + +static int mxser_ioctl_special(unsigned int cmd, unsigned long arg) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + int error, i, result, status; +#else + int i, result, status; +#endif + + switch ( cmd ) { + case MOXA_GET_CONF: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct mxser_hwconf)*4); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + copy_to_user((struct mxser_hwconf *)arg, mxsercfg, + sizeof(struct mxser_hwconf)*4); + return 0; + case MOXA_GET_MAJOR: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + copy_to_user((int*)arg, &ttymajor, sizeof(int)); + return 0; + + case MOXA_GET_CUMAJOR: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + copy_to_user((int*)arg, &calloutmajor, sizeof(int)); + return 0; + + case MOXA_CHKPORTENABLE: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + result = 0; + for ( i=0; itermios ) + GMStatus[i].cflag=mxvar_table[i].normal_termios.c_cflag; + else + GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag; + + status = inb(mxvar_table[i].base + UART_MSR); + if(status & 0x80/*UART_MSR_DCD*/) + GMStatus[i].dcd = 1; + else + GMStatus[i].dcd = 0; + + if(status & 0x20/*UART_MSR_DSR*/) + GMStatus[i].dsr = 1; + else + GMStatus[i].dsr = 0; + + + if(status & 0x10/*UART_MSR_CTS*/) + GMStatus[i].cts = 1; + else + GMStatus[i].cts = 0; + } + copy_to_user((struct mxser_mstatus *)arg, GMStatus, + sizeof(struct mxser_mstatus) * MXSER_PORTS); + return 0; + default: + return(-ENOIOCTLCMD); + } + return(0); +} + +/* + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + */ +static void mxser_throttle(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + + if ( I_IXOFF(tty) || (info->tty->termios->c_cflag & CRTSCTS) ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->IER &= ~MOXA_MUST_RECV_ISR; + outb(info->IER, info->base+UART_IER); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } +} + +static void mxser_unthrottle(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + + if ( I_IXOFF(tty) ) { + if ( info->x_char ) + info->x_char = 0; + else { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->IER |= MOXA_MUST_RECV_ISR; + outb(info->IER, info->base+UART_IER); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } + } + + if ( info->tty->termios->c_cflag & CRTSCTS ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->IER |= MOXA_MUST_RECV_ISR; + outb(info->IER, info->base+UART_IER); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } +} + +static void mxser_set_termios(struct tty_struct * tty, + struct termios * old_termios) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + +#if 0 // mask by Victor Yu. 01-04-2005 + if ( (tty->termios->c_cflag != old_termios->c_cflag) || + (RELEVANT_IFLAG(tty->termios->c_iflag) != + RELEVANT_IFLAG(old_termios->c_iflag)) ) { +#else // add by Victor Yu. 01-04-2005 + if ( (tty->termios->c_cflag != old_termios->c_cflag) || + (tty->termios->c_iflag != old_termios->c_iflag) ) { +#endif + + mxser_change_speed(info, old_termios); + + if ( (old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS) ) { + tty->hw_stopped = 0; + mxser_start(tty); + } + } + + /* Handle sw stopped */ + if ( (old_termios->c_iflag & IXON) && + !(tty->termios->c_iflag & IXON) ) { + tty->stopped = 0; + mxser_start(tty); + } +} + +/* + * mxser_stop() and mxser_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + */ +static void mxser_stop(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( info->IER & UART_IER_THRI ) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +static void mxser_start(struct tty_struct * tty) +{ + struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( info->xmit_cnt && info->xmit_buf && + !(info->IER & UART_IER_THRI) ) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) +/* + * mxser_wait_until_sent() --- wait until the transmitter is empty + */ +static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (info->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + orig_jiffies = jiffies + timeout; + while (!((lsr = inb(info->base+ UART_LSR)) & UART_LSR_TEMT)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0)) + set_current_state(TASK_INTERRUPTIBLE); +#else + current->state = TASK_INTERRUPTIBLE; +#endif + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies)) + break; + } +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0)) + set_current_state(TASK_RUNNING); +#else + current->state = TASK_RUNNING; +#endif + +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} +#endif + + +/* + * This routine is called by tty_hangup() when a hangup is signaled. + */ +void mxser_hangup(struct tty_struct * tty) +{ + struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; +#if 1 // add by Victor Yu. 12-28-2004 + unsigned long flags; +#endif + + mxser_flush_buffer(tty); + mxser_shutdown(info); +#if 0 // mask by Victor Yu. 12-28-2004 + info->event = 0; + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->event = 0; + info->count = 0; +#if 0 + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); +#else + info->flags &= ~(ASYNC_NORMAL_ACTIVE); +#endif + info->tty = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + wake_up_interruptible(&info->open_wait); +} + +/* + * This is the serial driver's generic interrupt routine + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static irqreturn_t mxser_interrupt(int irq, void *dev_id) +#else +static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs * regs) +#endif +{ + int status, iir, i; + struct mxser_struct * info; + struct mxser_struct * port=NULL; + int max, irqbits, msr; + int pass_counter=0, bits; + + for ( i=0; ivector) & port->vectormask; + if ( irqbits == port->vectormask ) + break; +#ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006 + for ( i=0, bits=1; ivectormask ) + break; + if ( bits & irqbits ) + continue; + info = port + i; + + // following add by Victor Yu. 09-13-2002 + iir = inb(info->base+UART_IIR); + if ( iir & UART_IIR_NO_INT ) + continue; + iir &= MOXA_MUST_IIR_MASK; + if ( !info->tty ) { // because the UART chip has bug. so need to do this + status = inb(info->base+UART_LSR); + outb(0x27, info->base+UART_FCR); + inb(info->base+UART_MSR); + continue; + } + // above add by Victor Yu. 09-13-2002 + +#if 1 // add by Victor Yu. 01-04-2005 + if ( iir == MOXA_MUST_IIR_XSC ) { + if ( !(inb(info->base+UART_MCR) & MOXA_MUST_MCR_XON_FLAG) ) { + info->icount.buf_overrun++; + wake_up_interruptible(&info->delta_msr_wait); + } + continue; + } +#endif + + if ( iir == MOXA_MUST_IIR_GDA || + iir == MOXA_MUST_IIR_RDA || + iir == MOXA_MUST_IIR_RTO || + iir == MOXA_MUST_IIR_LSR ) { + status = inb(info->base+UART_LSR); + mxser_receive_chars(info, &status); + } + msr = inb(info->base + UART_MSR); + if ( msr & UART_MSR_ANY_DELTA ) { + mxser_check_modem_status(info, msr); + } + + if ( iir == 0x02 ) + mxser_transmit_chars(info); + } + if ( pass_counter++ > MXSER_ISR_PASS_LIMIT ) { + break; /* Prevent infinite loops */ + } + } + return IRQ_HANDLED; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +#define BYPASS_FLIP // add by Victor Yu. 09-17-2004 +#endif +#define N_TTY_BUF_SIZE_MASK (N_TTY_BUF_SIZE-1) // add by Victor Yu. 02-04-2005 +static inline void mxser_receive_chars(struct mxser_struct *info, + int *status) +{ + struct tty_struct * tty = info->tty; + unsigned char ch, gdl; + int cnt = 0; +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + unsigned char *cp=tty->flip.char_buf; + char *fp=tty->flip.flag_buf; +#endif // BYPASS_FLIP + + // following add by Victor Yu. 09-02-2002 + if ( *status & (UART_LSR_SPECIAL|MOXA_MUST_LSR_RERR) ) + goto intr_old; + + gdl = inb(info->base+MOXA_MUST_GDL_REGISTER); + + // following add by Victor Yu. 10-13-2004 +#ifdef BYPASS_FLIP + cnt = gdl; +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007 + if ( tty->receive_room == 0 ) { + if ( I_IXOFF(tty) || (tty->termios->c_cflag & CRTSCTS) ) { // has flow control + cnt = gdl = MIN(gdl, tty->receive_room); + } else { + cnt = gdl; + } + } else { + cnt = gdl = MIN(gdl, tty->receive_room); + } +#else + cnt = gdl = MIN(gdl, TTY_FLIPBUF_SIZE-tty->flip.count); +#endif // LINUX_VERSION_CODE +#endif // BYPASS_FLIP + // above add by Victor Yu. 10-13-2004 + + while ( gdl-- ) { + ch = inb(info->base + UART_RX); +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *cp++ = ch; + *fp++ = 0; +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007 + tty_insert_flip_char(tty, ch, 0); +#else + tty->flip.count++; + *tty->flip.char_buf_ptr++ = ch; + *tty->flip.flag_buf_ptr++ = 0; +#endif // LINUX_VERSION_CODE +#endif // BYPASS_FLIP + } + goto end_intr; + +intr_old: + // above add by Victor Yu. 09-02-2002 + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007 + if ( tty->receive_room == 0 ) { + if ( I_IXOFF(tty) || (tty->termios->c_cflag & CRTSCTS) ) // has flow control + goto end_intr; + } +#endif + ch = inb(info->base + UART_RX); + + // following add by Victor Yu. 09-02-2002 + if ( (*status&UART_LSR_OE) && !(*status&UART_LSR_DR) ) + outb(0x23, info->base+UART_FCR); + +#if 1 // add by Victor Yu. 01-06-2005 + { + int __flag=0; + if ( *status & UART_LSR_BI ) { + info->icount.brk++; + __flag = 1; + } + if ( *status & UART_LSR_PE ) { + info->icount.parity++; + __flag = 1; + } + if ( *status & UART_LSR_FE ) { + info->icount.frame++; + __flag = 1; + } + if ( *status & UART_LSR_OE ) { + info->icount.overrun++; + __flag = 1; + } + if ( __flag ) + wake_up_interruptible(&info->delta_msr_wait); + } +#endif + + *status &= info->read_status_mask; + // above add by Victor Yu. 09-02-2002 + + if ( !(*status & info->ignore_status_mask) ) { + char flag; +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + if ( cnt >= TTY_FLIPBUF_SIZE ) + goto end_intr; +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-16-2007 + if ( tty->flip.count >= TTY_FLIPBUF_SIZE ) + goto end_intr; + tty->flip.count++; +#endif +#endif // BYPASS_FLIP + if ( *status & UART_LSR_SPECIAL ) { + if ( *status & UART_LSR_BI ) { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = TTY_BREAK; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = TTY_BREAK; +#else + flag = TTY_BREAK; +#endif +#endif + + if ( info->flags & ASYNC_SAK ) + do_SAK(tty); + } else if ( *status & UART_LSR_PE ) { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = TTY_PARITY; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = TTY_PARITY; +#else + flag = TTY_PARITY; +#endif +#endif + } else if ( *status & UART_LSR_FE ) { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = TTY_FRAME; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = TTY_FRAME; +#else + flag = TTY_FRAME; +#endif +#endif + } else if ( *status & UART_LSR_OE ) { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = TTY_OVERRUN; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; +#else + flag = TTY_OVERRUN; +#endif +#endif + } else { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = 0; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = 0; +#else + flag = 0; +#endif +#endif + } + } else { +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *fp++ = 0; +#else +#if 0 // mask by Victor Yu. 02-08-2007 + *tty->flip.flag_buf_ptr++ = 0; +#else + flag = 0; +#endif +#endif // BYPASS_FLIP + } +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + *cp++ = ch; +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007 + tty_insert_flip_char(tty, ch, flag); +#else + *tty->flip.char_buf_ptr++ = ch; +#endif +#endif // BYPASS_FLIP + cnt++; + } + +end_intr: // add by Victor Yu. 09-02-2002 + + mxvar_log.rxcnt[info->port] += cnt; + +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) // add by Victor Yu. 02-04-2005 + info->icount.rx += cnt; +#endif + +/* added by casper 1/11/2000 */ +#ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004 + tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, cnt); +#else +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) + tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif // LINUX_VERSION_CODE +#endif // BYPASS_FLIP +} + +static inline void mxser_transmit_chars(struct mxser_struct *info) +{ + int count, cnt; + + if ( info->x_char ) { + outb(info->x_char, info->base + UART_TX); + info->x_char = 0; + mxvar_log.txcnt[info->port]++; +/* added by casper 1/11/2000 */ +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) + info->icount.tx++; +#endif +/* */ + return; + } + + if ( info->xmit_buf == 0 ) + return; + + if ((info->xmit_cnt <= 0) || info->tty->stopped || + (info->tty->hw_stopped && (info->type != PORT_16550A))) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + return; + } + +#if 0 // mask by Victor Yu. 10-12-2004 + cnt = info->xmit_cnt; + count = info->xmit_fifo_size; + do { + outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + if ( --info->xmit_cnt <= 0 ) + break; + } while ( --count > 0 ); + mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt); +#else // add by Victor Yu. 10-12-2004 + { + int tail=info->xmit_tail; + unsigned char *ptr=info->xmit_buf; +#define XMIT_SIZE_MASK (SERIAL_XMIT_SIZE - 1) + cnt = count = MIN(info->xmit_fifo_size, info->xmit_cnt); + while ( count-- > 0 ) { + outb(ptr[tail++], info->base); + tail &= XMIT_SIZE_MASK; + } + info->xmit_tail = tail; + info->xmit_cnt -= cnt; + mxvar_log.txcnt[info->port] += cnt; + } +#endif + +/* added by casper 1/11/2000 */ +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) +#if 0 // mask by Victor Yu. 10-12-2004 + info->icount.tx += (cnt - info->xmit_cnt); +#else // add by Victor Yu. 10-12-2004 + info->icount.tx += cnt; +#endif +#endif +/* */ + + if ( info->xmit_cnt < WAKEUP_CHARS ) { + set_bit(MXSER_EVENT_TXLOW,&info->event); +#if 0 + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; + queue_task(&info->tqueue,&tq_scheduler); +#else + schedule_work(&info->tqueue); +#endif + } + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } +} + +static inline void mxser_check_modem_status(struct mxser_struct *info, + int status) +{ + /* update input line counters */ + if ( status & UART_MSR_TERI ) + info->icount.rng++; + if ( status & UART_MSR_DDSR ) + info->icount.dsr++; + if ( status & UART_MSR_DDCD ) + info->icount.dcd++; + if ( status & UART_MSR_DCTS ) + info->icount.cts++; + wake_up_interruptible(&info->delta_msr_wait); + + if ( (info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD) ) { + if ( status & UART_MSR_DCD ) + wake_up_interruptible(&info->open_wait); +#if 0 + else if ( !((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP)) ) +#else + else +#endif + set_bit(MXSER_EVENT_HANGUP,&info->event); +#if 0 + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; +#else + schedule_work(&info->tqueue); +#endif + } + if ( info->flags & ASYNC_CTS_FLOW ) { + if ( info->tty->hw_stopped ) { + if (status & UART_MSR_CTS ){ + info->tty->hw_stopped = 0; + + if (info->type != PORT_16550A) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + set_bit(MXSER_EVENT_TXLOW,&info->event); +#if 0 + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; +#else + schedule_work(&info->tqueue); +#endif + } + } else { + if ( !(status & UART_MSR_CTS) ){ + info->tty->hw_stopped = 1; + if (info->type != PORT_16550A) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + } + } + } +} + +static int mxser_block_til_ready(struct tty_struct *tty, struct file * filp, + struct mxser_struct *info) +{ +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) + DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue wait = { current, NULL }; +#endif + unsigned long flags; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if ( tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING) ) { + if ( info->flags & ASYNC_CLOSING ) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if ( info->flags & ASYNC_HUP_NOTIFY ) + return(-EAGAIN); + else + return(-ERESTARTSYS); +#else + return(-EAGAIN); +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ +#if 0 + if ( tty->driver->subtype == SERIAL_TYPE_CALLOUT ) { + if ( info->flags & ASYNC_NORMAL_ACTIVE ) + return(-EBUSY); + if ( (info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session) ) + return(-EBUSY); + if ( (info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp) ) + return(-EBUSY); + info->flags |= ASYNC_CALLOUT_ACTIVE; + return(0); + } +#endif + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ( (filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR)) ) { +#if 0 + if ( info->flags & ASYNC_CALLOUT_ACTIVE ) + return(-EBUSY); +#endif + info->flags |= ASYNC_NORMAL_ACTIVE; + return(0); + } + +#if 0 + if ( info->flags & ASYNC_CALLOUT_ACTIVE ) { + if ( info->normal_termios.c_cflag & CLOCAL ) + do_clocal = 1; + } else { +#endif + if ( tty->termios->c_cflag & CLOCAL ) + do_clocal = 1; +#if 0 + } +#endif + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * mxser_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#if 0 // mask by Victor Yu. 12-28-2004 + save_flags(flags); + cli(); + if ( !tty_hung_up_p(filp) ) + info->count--; + restore_flags(flags); +// #else // add by Victor Yu. 12-28-2004, remark by Victor Yu. 06-22-2007 + if ( !tty_hung_up_p(filp) ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->count--; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } +#endif + info->blocked_open++; + while ( 1 ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#if 0 + if ( !(info->flags & ASYNC_CALLOUT_ACTIVE) ) +#endif + outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, + info->base + UART_MCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + current->state = TASK_INTERRUPTIBLE; + if ( tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ) { +#ifdef SERIAL_DO_RESTART + if ( info->flags & ASYNC_HUP_NOTIFY ) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } +#if 0 + if ( !(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)) ) +#else + if ( !(info->flags & ASYNC_CLOSING) && + (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)) ) +#endif + break; + if ( signal_pending(current) ) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if ( !tty_hung_up_p(filp) ) { +#if 0 // mask by Victor 12-28-2004 + info->count++; +// #else // add by Victor Yu. 12-28-2004, remark by Victor Yu. 06-22-2007 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->count++; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + } + info->blocked_open--; + if ( retval ) + return(retval); + info->flags |= ASYNC_NORMAL_ACTIVE; + return(0); +} + +static int mxser_startup(struct mxser_struct * info) +{ + unsigned long flags; + unsigned long page; + + page = get_zeroed_page(GFP_KERNEL); + if ( !page ) + return(-ENOMEM); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + + if ( info->flags & ASYNC_INITIALIZED ) { + free_page(page); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(0); + } + + if ( !info->base || !info->type ) { + if ( info->tty ) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(0); + } + if ( info->xmit_buf ) + free_page(page); + else + info->xmit_buf = (unsigned char *)page; + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in mxser_change_speed()) + */ + if ( info->xmit_fifo_size == 16 ) + outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), + info->base + UART_FCR); + // following add by Victor Yu. 08-30-2002 + else if ( info->xmit_fifo_size == 64 || info->xmit_fifo_size == 128 ) + outb((UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT|MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base+UART_FCR); + // above add by Victor Yu. 08-30-2002 + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if ( inb(info->base + UART_LSR) == 0xff ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) + if ( suser() ) { +#else + if (capable(CAP_SYS_ADMIN)) { +#endif + if ( info->tty ) + set_bit(TTY_IO_ERROR, &info->tty->flags); + return(0); + } else + return(-ENODEV); + } + + /* + * Clear the interrupt registers. + */ + (void)inb(info->base + UART_LSR); + (void)inb(info->base + UART_RX); + (void)inb(info->base + UART_IIR); + (void)inb(info->base + UART_MSR); + + /* + * Now, initialize the UART + */ + outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */ + info->MCR = UART_MCR_DTR | UART_MCR_RTS; + outb(info->MCR, info->base + UART_MCR); + + /* + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI | MOXA_MUST_IER_EGDAI; + outb(info->IER, info->base + UART_IER); /* enable interrupts */ + + /* + * And clear the interrupt registers again for luck. + */ + (void)inb(info->base + UART_LSR); + (void)inb(info->base + UART_RX); + (void)inb(info->base + UART_IIR); + (void)inb(info->base + UART_MSR); + +#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) + if ( info->tty ) + clear_bit(TTY_IO_ERROR, &info->tty->flags); +#else + if ( info->tty ) + test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags); +#endif + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ +#if 1 // add by Victor Yu. 12-27-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + mxser_change_speed(info, 0); + +#if 1 // add by Victor Yu. 12-27-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + info->flags |= ASYNC_INITIALIZED; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(0); +} + +/* + * This routine will shutdown a serial port; interrupts maybe disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void mxser_shutdown(struct mxser_struct * info) +{ + unsigned long flags; + + if ( !(info->flags & ASYNC_INITIALIZED) ) + return; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); /* Disable interrupts */ +#endif // LINUX_VERSION_CODE + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ, if necessary + */ + if ( info->xmit_buf ) { + free_page((unsigned long)info->xmit_buf); + info->xmit_buf = 0; + } + + info->IER = 0; + outb(0x00, info->base + UART_IER); + + if ( !info->tty || (info->tty->termios->c_cflag & HUPCL) ) + info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); + outb(info->MCR, info->base + UART_MCR); + + /* clear Rx/Tx FIFO's */ + outb((UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT|MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR); + + /* read data port to reset things */ + (void)inb(info->base + UART_RX); + + if ( info->tty ) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static int mxser_change_speed(struct mxser_struct *info, + struct termios *old_termios) +{ + int quot = 0; + unsigned cflag, cval, fcr; + int bindex; + int ret = 0; + unsigned long flags; + + if ( !info->tty || !info->tty->termios ) + return ret; + cflag = info->tty->termios->c_cflag; + if ( !(info->base) ) + return ret; + +#ifndef B921600 +#define B921600 (B460800 +1) +#endif + switch( cflag & (CBAUD | CBAUDEX) ){ +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004 + case B4000000 : bindex = BAUD_TABLE_NO; break; +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) /// add by Victor Yu. 02-16-2007 + case B921600 : bindex = 22; break; + case B576000 : bindex = 21; break; + case B500000 : bindex = 20; break; +#else + case B921600 : bindex = 20; break; +#endif + case B460800 : bindex = 19; break; + case B230400 : bindex = 18; break; + case B115200 : bindex = 17; break; + case B57600 : bindex = 16; break; + case B38400 : bindex = 15; break; + case B19200 : bindex = 14; break; + case B9600 : bindex = 13; break; + case B4800 : bindex = 12; break; + case B2400 : bindex = 11; break; + case B1800 : bindex = 10; break; + case B1200 : bindex = 9; break; + case B600 : bindex = 8; break; + case B300 : bindex = 7; break; + case B200 : bindex = 6; break; + case B150 : bindex = 5; break; + case B134 : bindex = 4; break; + case B110 : bindex = 3; break; + case B75 : bindex = 2; break; + case B50 : bindex = 1; break; + default: bindex = 0; break; + } + + if ( bindex == 15 ) { + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI ) + bindex = 16; /* 57600 bps */ + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) + bindex = 17; /* 115200 bps */ + +#ifdef ASYNC_SPD_SHI + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + bindex = 18; +#endif + +#ifdef ASYNC_SPD_WARP + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + bindex = 19; +#endif + } +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004 + if ( bindex == BAUD_TABLE_NO ) { + quot = info->baud_base / info->speed; + if ( info->speed <= 0 || info->speed > info->MaxCanSetBaudRate ) + quot = 0; + } + else +#endif + if ( mxvar_baud_table[bindex] == 134 ) { + quot = (2 * info->baud_base / 269); +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + info->speed = 134; +#endif + } else if ( mxvar_baud_table[bindex] ) { + quot = info->baud_base / mxvar_baud_table[bindex]; + // following add by Victor Yu. 09-04-2002 + if ( mxvar_baud_table[bindex] > info->MaxCanSetBaudRate ) + quot = 0; + // add by Victor Yu. 09-04-2002 +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + info->speed = mxvar_baud_table[bindex]; +#endif + if (!quot && old_termios) { + /* re-calculate */ + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + switch( info->tty->termios->c_cflag & (CBAUD | CBAUDEX) ){ +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004 + case B4000000 : bindex = BAUD_TABLE_NO; break; +#endif + case B921600 : bindex = 20; break; + case B460800 : bindex = 19; break; + case B230400 : bindex = 18; break; + case B115200 : bindex = 17; break; + case B57600 : bindex = 16; break; + case B38400 : bindex = 15; break; + case B19200 : bindex = 14; break; + case B9600 : bindex = 13; break; + case B4800 : bindex = 12; break; + case B2400 : bindex = 11; break; + case B1800 : bindex = 10; break; + case B1200 : bindex = 9; break; + case B600 : bindex = 8; break; + case B300 : bindex = 7; break; + case B200 : bindex = 6; break; + case B150 : bindex = 5; break; + case B134 : bindex = 4; break; + case B110 : bindex = 3; break; + case B75 : bindex = 2; break; + case B50 : bindex = 1; break; + default: bindex = 0; break; + } + if ( bindex == 15 ) { + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI ) + bindex = 16; /* 57600 bps */ + if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) + bindex = 17; /* 115200 bps */ +#ifdef ASYNC_SPD_SHI + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + bindex = 18; +#endif +#ifdef ASYNC_SPD_WARP + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + bindex = 19; +#endif + } +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004 + if ( bindex == BAUD_TABLE_NO ) { + quot = info->baud_base / info->speed; + if ( info->speed <= 0 || info->speed > info->MaxCanSetBaudRate ) + quot = 0; + } + else +#endif + if ( mxvar_baud_table[bindex] == 134 ) { + quot = (2 * info->baud_base / 269); +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + info->speed = 134; +#endif + } else if ( mxvar_baud_table[bindex] ) { + quot = info->baud_base / mxvar_baud_table[bindex]; + // following add by Victor Yu. 09-04-2002 + if ( mxvar_baud_table[bindex] > info->MaxCanSetBaudRate ) + quot = 0; + // above add by Victor Yu. 09-04-2002 +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + info->speed = mxvar_baud_table[bindex]; +#endif + if(quot==0) + quot = 1; + } else { + quot = 0; + } + }else if(quot==0) + quot = 1; + } else { + quot = 0; + } + + info->timeout = ((info->xmit_fifo_size*HZ*10*quot) / info->baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if ( quot ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->MCR |= UART_MCR_DTR; + outb(info->MCR, info->base + UART_MCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } else { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + info->MCR &= ~UART_MCR_DTR; + outb(info->MCR, info->base + UART_MCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return ret; + } + /* byte size and parity */ + switch ( cflag & CSIZE ) { + case CS5: cval = 0x00; break; + case CS6: cval = 0x01; break; + case CS7: cval = 0x02; break; + case CS8: cval = 0x03; break; + default: cval = 0x00; break; /* too keep GCC shut... */ + } + if ( cflag & CSTOPB ) + cval |= 0x04; + if ( cflag & PARENB ) + cval |= UART_LCR_PARITY; +#ifndef CMSPAR +#define CMSPAR 010000000000 +#endif + if ( !(cflag & PARODD) ){ + cval |= UART_LCR_EPAR; + } + if ( cflag & CMSPAR ) + cval |= UART_LCR_SPAR; + + if ( (info->type == PORT_8250) || (info->type == PORT_16450) ) { + fcr = 0; + } else { + fcr = UART_FCR_ENABLE_FIFO; + // following add by Victor Yu. 08-30-2002 + fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; +#if 1 // add by Victor Yu. 05-04-2005 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + SET_MOXA_MUST_FIFO_VALUE(info); +#if 1 // add by Victor Yu. 05-04-2005 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + } + + /* CTS flow control flag and modem status interrupts */ +#if 1 // add by Victor Yu. 12-30-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#if 1 // add by Victor Yu. 05-04-2005 + outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */ + outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */ + outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */ + outb(cval, info->base + UART_LCR); /* reset DLAB */ +#ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004 + if ( info->speed ) { + quot = info->baud_base % info->speed; + quot *= 8; + if ( (quot % info->speed) > (info->speed / 2) ) { + quot /= info->speed; + quot++; + } else { + quot /= info->speed; + } + SET_MOXA_MUST_ENUM_VALUE(info->base, quot); + } else { + SET_MOXA_MUST_ENUM_VALUE(info->base, 0); + } +#endif + outb(fcr, info->base + UART_FCR); /* set fcr */ +#endif // 05-04-2005 +#endif // 12-30-2004 +#if 0 // mask by Victor Yu. 12-31-2004 + info->IER &= ~UART_IER_MSI; +#endif + info->MCR &= ~UART_MCR_AFE; + if ( cflag & CRTSCTS ) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + if ( info->type == PORT_16550A ) { + info->MCR |= UART_MCR_AFE; + } else { + unsigned char status; +#if 0 // mask by Victor Yu. 12-30-2004 + save_flags(flags); + cli(); +#endif + status = inb(info->base + UART_MSR); +#if 0 // mask by Victor Yu. 12-30-2004 + restore_flags(flags); +#endif + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { + info->tty->hw_stopped = 0; + if (info->type != PORT_16550A) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + set_bit(MXSER_EVENT_TXLOW, &info->event); +#if 0 + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; +#else + schedule_work(&info->tqueue); +#endif + } + } else { + if (!(status & UART_MSR_CTS)) { + info->tty->hw_stopped = 1; + if (info->type != PORT_16550A) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + } + } + } + } else { + info->flags &= ~ASYNC_CTS_FLOW; + } +#if 0 // add by Victor Yu. 12-27-2004 + save_flags(flags); + cli(); +#endif + outb(info->MCR, info->base + UART_MCR); + if ( cflag & CLOCAL ){ + info->flags &= ~ASYNC_CHECK_CD; + }else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + outb(info->IER, info->base + UART_IER); +#if 1 // add by Victor Yu. 12-27-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + + /* + * Set up parity check flag + */ + info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if ( I_INPCK(info->tty) ) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if ( I_BRKINT(info->tty) || I_PARMRK(info->tty) ) + info->read_status_mask |= UART_LSR_BI; + + info->ignore_status_mask = 0; +#if 0 + /* This should be safe, but for some broken bits of hardware... */ + if ( I_IGNPAR(info->tty) ) { + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; + } +#endif + if ( I_IGNBRK(info->tty) ) { + info->ignore_status_mask |= UART_LSR_BI; + info->read_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if ( I_IGNPAR(info->tty) ) { + info->ignore_status_mask |= UART_LSR_OE|UART_LSR_PE|UART_LSR_FE; + info->read_status_mask |= UART_LSR_OE|UART_LSR_PE|UART_LSR_FE; + } + } + + // following add by Victor Yu. 09-02-2002 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty)); + SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty)); + if ( I_IXON(info->tty) ) { +#if 1 // add by Victor Yu. 01-04-2005 + info->IER |= MOXA_MUST_IER_XINT; +#endif + ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); + } else { +#if 1 // add by Victor Yu. 01-04-2005 + info->IER &= ~MOXA_MUST_IER_XINT; +#endif + DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); + } +#if 1 // add by Victor Yu. 01-04-2005 + outb(info->IER, info->base+UART_IER); +#endif + if ( I_IXOFF(info->tty) ) { + ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base); + } else { + DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base); + } + if ( I_IXANY(info->tty) ) { + info->MCR |= MOXA_MUST_MCR_XON_ANY; + ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base); + } else { + info->MCR &= ~MOXA_MUST_MCR_XON_ANY; + DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + // above add by Victor Yu. 09-02-2002 + + return ret; +} + +/* + * ------------------------------------------------------------ + * friends of mxser_ioctl() + * ------------------------------------------------------------ + */ +static int mxser_get_serial_info(struct mxser_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if ( !retinfo ) + return(-EFAULT); + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->port; + tmp.port = info->base; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + tmp.hub6 = 0; + copy_to_user(retinfo, &tmp, sizeof(*retinfo)); + return(0); +} + +static int mxser_set_serial_info(struct mxser_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + unsigned int flags; + int retval = 0; + + if ( !new_info || !info->base ) + return(-EFAULT); + copy_from_user(&new_serial, new_info, sizeof(new_serial)); + + if ( (new_serial.irq != info->irq) || + (new_serial.port != info->base) || + (new_serial.custom_divisor != info->custom_divisor) || + (new_serial.baud_base != info->baud_base) ) + return(-EPERM); + + flags = info->flags & ASYNC_SPD_MASK; + +#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) + if ( !suser() ) { +#else + if ( !capable(CAP_SYS_ADMIN)) { +#endif + if ( (new_serial.baud_base != info->baud_base) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK)) ) + return(-EPERM); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + } else { + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->close_delay = new_serial.close_delay * HZ/100; + info->closing_wait = new_serial.closing_wait * HZ/100; +#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + } + +/* added by casper, 3/17/2000, for mouse */ + info->type = new_serial.type; + + info->xmit_fifo_size = 128; + if ( info->flags & ASYNC_INITIALIZED ) { + if ( flags != (info->flags & ASYNC_SPD_MASK) ){ + mxser_change_speed(info,0); + } + } else{ + retval = mxser_startup(info); + } + return(retval); +} + +/* + * mxser_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 int mxser_get_lsr_info(struct mxser_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + status = inb(info->base + UART_LSR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + put_to_user(result, value); + return(0); +} + +/* + * This routine sends a break character out the serial port. + */ +static void mxser_send_break(struct mxser_struct * info, int duration) +{ + unsigned long flags; +#if 1 // add by Victor Yu. 12-27-2004 + unsigned long timeout; +#endif + + if ( !info->base ) + return; +#if 0 // mask by Victor Yu. 12-27-2004 + current->state = TASK_INTERRUPTIBLE; +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR); +#if 0 // mask by Victor Yu. 12-27-2004 + schedule_timeout(duration); +#else // add by Victor Yu. 12-27-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + timeout = jiffies + (unsigned long)duration; + while ( 1 ) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(5); + if ( time_after(jiffies, timeout) ) + break; + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} + +#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x +static int mxser_get_modem_info(struct mxser_struct * info, + unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + control = info->MCR; + status = inb(info->base + UART_MSR); +#if 0 // mask by Victor Yu. 12-30-2004, I think that we donot need to do it. Because the interrupt service will do it. + if ( status & UART_MSR_ANY_DELTA ) + mxser_check_modem_status(info, status); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | + ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | + ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | + ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | + ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | + ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + put_to_user(result, value); + return(0); +} + +static int mxser_set_modem_info(struct mxser_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007 + error = verify_area(VERIFY_READ, value, sizeof(int)); + if ( error ) + return(error); +#endif // LINUX_VERSION_CODE + get_from_user(arg,value); +#if 1 // add by Victor Yu. 12-30-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + switch ( cmd ) { + case TIOCMBIS: + if ( arg & TIOCM_RTS ) + info->MCR |= UART_MCR_RTS; + if ( arg & TIOCM_DTR ) + info->MCR |= UART_MCR_DTR; + break; + case TIOCMBIC: + if ( arg & TIOCM_RTS ) + info->MCR &= ~UART_MCR_RTS; + if ( arg & TIOCM_DTR ) + info->MCR &= ~UART_MCR_DTR; + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) | + ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) | + ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: +#if 1 // add by Victor Yu. 12-30-2004 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + return(-EINVAL); + } +#if 0 // mask by Victor Yu. 12-30-2004 + save_flags(flags); + cli(); +#endif + outb(info->MCR, info->base + UART_MCR); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + return(0); +} +#endif diff --git a/drivers/char/resetswitch.c b/drivers/char/resetswitch.c new file mode 100644 index 00000000..de1f7fbb --- /dev/null +++ b/drivers/char/resetswitch.c @@ -0,0 +1,138 @@ +/***************************************************************************/ + +/* + * linux/drivers/char/resetswitch.c + * + * Basic driver to support the Moxart software reset button. + * + * Jimmy_chen@moxa.com.tw + */ + +/***************************************************************************/ + +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESET_POLL_TIME (HZ/5) +#define RESET_TIMEOUT (HZ * 5) + +#define PIO(x) 1< +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SWITCH_IRQ IRQ_GPIO +#define MOXA_GPIO_DATAOUT 0x0 +#define MOXA_GPIO_DATAIN 0x04 +#define MOXA_GPIO_PINDIR 0x08 +#define MOXA_GPIO_DATASET 0x10 +#define MOXA_GPIO_DATACLEAR 0x14 +#define MOXA_GPIO_PPENABLE 0x18 +#define MOXA_GPIO_PPTYPE 0x1C +#define MOXA_GPIO_INTENABLE 0x20 +#define MOXA_GPIO_INTRAWSTATE 0x24 +#define MOXA_GPIO_INTMASKSTATE 0x28 +#define MOXA_GPIO_INTMASK 0x2C +#define MOXA_GPIO_INTCLEAR 0x30 +#define MOXA_GPIO_INTTRIG 0x34 +#define MOXA_GPIO_INTBOTH 0x38 +#define MOXA_GPIO_INTRISENEG 0x3C +#define MOXA_GPIO_BOUNCEENABLE 0x40 +#define MOXA_GPIO_BOUNCEPRESCALE 0x44 +/* watch dog counter */ +#define WDBASE CPE_WATCHDOG_BASE +#define WDLOAD 0x04 +#define WDRESTART 0x08 +#define WDCR 0x0C +#define WDSTATUS 0x10 +#define WDCLEAR 0x14 +#define WDINTRLEN 0x18 +#define WDPASSWD 0x5AB9 +#define PIO(x) 1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ +#ifdef CONFIG_M5272 +/***************************************************************************/ + +/* + * Off-course the 5272 would have to deal with setting up and + * acknowledging interrupts differently to all other ColdFIre's! + */ +#define SWITCH_IRQ 65 + +static void __inline__ mcf_enablevector(int vecnr) +{ + volatile unsigned long *icrp; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0xf0000000; +} + +static void __inline__ mcf_disablevector(void) +{ + volatile unsigned long *icrp; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0x80000000; +} + +static void __inline__ mcf_ackvector(void) +{ + volatile unsigned long *icrp; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0xf0000000; +} + +static __inline__ int mcf_isvector(void) +{ + return((*((volatile unsigned long *) (MCF_MBAR + MCFSIM_ISR)) & 0x80000000) == 0); +} + +/***************************************************************************/ +#else +/***************************************************************************/ + +/* + * Common vector setup for 5206e, 5307 and 5407. + */ +#define SWITCH_IRQ 31 + +static void __inline__ mcf_enablevector(int vecnr) +{ +} + +static void __inline__ mcf_disablevec(void) +{ + mcf_setimr(mcf_getimr() | MCFSIM_IMR_EINT7); +} + +static void __inline__ mcf_ackvector(void) +{ + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT7); +} + +static __inline__ int mcf_isvector(void) +{ + return(mcf_getipr() & MCFSIM_IMR_EINT7); +} + +/***************************************************************************/ +#endif /* !CONFIG_M5272 */ +/***************************************************************************/ + +void resetswitch_button(int irq, void *dev_id, struct pt_regs *regs) +{ + extern void flash_eraseconfig(void); + static int inbutton = 0; + + /* + * IRQ7 is not maskable by the CPU core. It is possible + * that switch bounce mey get us back here before we have + * really serviced the interrupt. + */ + if (inbutton) + return; + inbutton = 1; + + /* Disable interrupt at SIM - best we can do... */ +#if 0 + mcf_disablevec(); +#endif + + /* Try and de-bounce the switch a little... */ + udelay(10000); + +#ifdef CONFIG_BLK_DEV_BLKMEM + flash_eraseconfig(); +#endif + + /* Don't leave here 'till button is no longer pushed! */ + for (;;) { + if (mcf_isvector() != 0) + break; + } + + HARD_RESET_NOW(); + /* Should never get here... */ + + inbutton = 0; + + mcf_ackvector(); +} + +/***************************************************************************/ + +int resetswitch_init(void) +{ + mcf_enablevector(SWITCH_IRQ); + mcf_autovector(SWITCH_IRQ); + request_irq(SWITCH_IRQ, resetswitch_button, + (SA_INTERRUPT | IRQ_FLG_FAST), "Reset Button", NULL); + return(0); +} + +module_init(resetswitch_init); + +/***************************************************************************/ diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c dissimilarity index 91% index 66a7385b..19aad46a 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1,1380 +1,462 @@ -/* - * Real Time Clock interface for Linux - * - * Copyright (C) 1996 Paul Gortmaker - * - * This driver allows use of the real time clock (built into - * nearly all computers) from user space. It exports the /dev/rtc - * interface supporting various ioctl() and also the - * /proc/driver/rtc pseudo-file for status information. - * - * The ioctls can be used to set the interrupt behaviour and - * generation rate from the RTC via IRQ 8. Then the /dev/rtc - * interface can be used to make use of these timer interrupts, - * be they interval or alarm based. - * - * The /dev/rtc interface will block on reads until an interrupt - * has been received. If a RTC interrupt has already happened, - * it will output an unsigned long and then block. The output value - * contains the interrupt status in the low byte and the number of - * interrupts since the last read in the remaining high bytes. The - * /dev/rtc interface can also be used with the select(2) call. - * - * 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. - * - * Based on other minimal char device drivers, like Alan's - * watchdog, Ted's random, etc. etc. - * - * 1.07 Paul Gortmaker. - * 1.08 Miquel van Smoorenburg: disallow certain things on the - * DEC Alpha as the CMOS clock is also used for other things. - * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. - * 1.09a Pete Zaitcev: Sun SPARC - * 1.09b Jeff Garzik: Modularize, init cleanup - * 1.09c Jeff Garzik: SMP cleanup - * 1.10 Paul Barton-Davis: add support for async I/O - * 1.10a Andrea Arcangeli: Alpha updates - * 1.10b Andrew Morton: SMP lock fix - * 1.10c Cesar Barros: SMP locking fixes and cleanup - * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit - * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. - * 1.11 Takashi Iwai: Kernel access functions - * rtc_register/rtc_unregister/rtc_control - * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init - * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer - * CONFIG_HPET_EMULATE_RTC - * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. - * 1.12ac Alan Cox: Allow read access to the day of week register - */ - -#define RTC_VERSION "1.12ac" - -/* - * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with - * interrupts disabled. Due to the index-port/data-port (0x70/0x71) - * design of the RTC, we don't want two different things trying to - * get to it at once. (e.g. the periodic 11 min sync from time.c vs. - * this driver.) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(__i386__) -#include -#endif - -#ifdef __sparc__ -#include -#include -#ifdef __sparc_v9__ -#include -#endif - -static unsigned long rtc_port; -static int rtc_irq = PCI_IRQ_NONE; -#endif - -#ifdef CONFIG_HPET_RTC_IRQ -#undef RTC_IRQ -#endif - -#ifdef RTC_IRQ -static int rtc_has_irq = 1; -#endif - -#ifndef CONFIG_HPET_EMULATE_RTC -#define is_hpet_enabled() 0 -#define hpet_set_alarm_time(hrs, min, sec) 0 -#define hpet_set_periodic_freq(arg) 0 -#define hpet_mask_rtc_irq_bit(arg) 0 -#define hpet_set_rtc_irq_bit(arg) 0 -#define hpet_rtc_timer_init() do { } while (0) -#define hpet_rtc_dropped_irq() 0 -static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;} -#else -extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); -#endif - -/* - * We sponge a minor off of the misc major. No need slurping - * up another valuable major dev number for this. If you add - * an ioctl, make sure you don't conflict with SPARC's RTC - * ioctls. - */ - -static struct fasync_struct *rtc_async_queue; - -static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); - -#ifdef RTC_IRQ -static struct timer_list rtc_irq_timer; -#endif - -static ssize_t rtc_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); - -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - -#ifdef RTC_IRQ -static unsigned int rtc_poll(struct file *file, poll_table *wait); -#endif - -static void get_rtc_alm_time (struct rtc_time *alm_tm); -#ifdef RTC_IRQ -static void rtc_dropped_irq(unsigned long data); - -static void set_rtc_irq_bit_locked(unsigned char bit); -static void mask_rtc_irq_bit_locked(unsigned char bit); - -static inline void set_rtc_irq_bit(unsigned char bit) -{ - spin_lock_irq(&rtc_lock); - set_rtc_irq_bit_locked(bit); - spin_unlock_irq(&rtc_lock); -} - -static void mask_rtc_irq_bit(unsigned char bit) -{ - spin_lock_irq(&rtc_lock); - mask_rtc_irq_bit_locked(bit); - spin_unlock_irq(&rtc_lock); -} -#endif - -static int rtc_proc_open(struct inode *inode, struct file *file); - -/* - * Bits in rtc_status. (6 bits of room for future expansion) - */ - -#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ -#define RTC_TIMER_ON 0x02 /* missed irq timer active */ - -/* - * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is - * protected by the big kernel lock. However, ioctl can still disable the timer - * in rtc_status and then with del_timer after the interrupt has read - * rtc_status but before mod_timer is called, which would then reenable the - * timer (but you would need to have an awful timing before you'd trip on it) - */ -static unsigned long rtc_status = 0; /* bitmapped status byte. */ -static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ -static unsigned long rtc_irq_data = 0; /* our output to the world */ -static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ - -#ifdef RTC_IRQ -/* - * rtc_task_lock nests inside rtc_lock. - */ -static DEFINE_SPINLOCK(rtc_task_lock); -static rtc_task_t *rtc_callback = NULL; -#endif - -/* - * If this driver ever becomes modularised, it will be really nice - * to make the epoch retain its value across module reload... - */ - -static unsigned long epoch = 1900; /* year corresponding to 0x00 */ - -static const unsigned char days_in_mo[] = -{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/* - * Returns true if a clock update is in progress - */ -static inline unsigned char rtc_is_updating(void) -{ - unsigned long flags; - unsigned char uip; - - spin_lock_irqsave(&rtc_lock, flags); - uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irqrestore(&rtc_lock, flags); - return uip; -} - -#ifdef RTC_IRQ -/* - * A very tiny interrupt handler. It runs with IRQF_DISABLED set, - * but there is possibility of conflicting with the set_rtc_mmss() - * call (the rtc irq and the timer irq can easily run at the same - * time in two different CPUs). So we need to serialize - * accesses to the chip with the rtc_lock spinlock that each - * architecture should implement in the timer code. - * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) - */ - -irqreturn_t rtc_interrupt(int irq, void *dev_id) -{ - /* - * Can be an alarm interrupt, update complete interrupt, - * or a periodic interrupt. We store the status in the - * low byte and the number of interrupts received since - * the last read in the remainder of rtc_irq_data. - */ - - spin_lock (&rtc_lock); - rtc_irq_data += 0x100; - rtc_irq_data &= ~0xff; - if (is_hpet_enabled()) { - /* - * In this case it is HPET RTC interrupt handler - * calling us, with the interrupt information - * passed as arg1, instead of irq. - */ - rtc_irq_data |= (unsigned long)irq & 0xF0; - } else { - rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); - } - - if (rtc_status & RTC_TIMER_ON) - mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - - spin_unlock (&rtc_lock); - - /* Now do the rest of the actions */ - spin_lock(&rtc_task_lock); - if (rtc_callback) - rtc_callback->func(rtc_callback->private_data); - spin_unlock(&rtc_task_lock); - wake_up_interruptible(&rtc_wait); - - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); - - return IRQ_HANDLED; -} -#endif - -/* - * sysctl-tuning infrastructure. - */ -static ctl_table rtc_table[] = { - { - .ctl_name = 1, - .procname = "max-user-freq", - .data = &rtc_max_user_freq, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { .ctl_name = 0 } -}; - -static ctl_table rtc_root[] = { - { - .ctl_name = 1, - .procname = "rtc", - .maxlen = 0, - .mode = 0555, - .child = rtc_table, - }, - { .ctl_name = 0 } -}; - -static ctl_table dev_root[] = { - { - .ctl_name = CTL_DEV, - .procname = "dev", - .maxlen = 0, - .mode = 0555, - .child = rtc_root, - }, - { .ctl_name = 0 } -}; - -static struct ctl_table_header *sysctl_header; - -static int __init init_sysctl(void) -{ - sysctl_header = register_sysctl_table(dev_root, 0); - return 0; -} - -static void __exit cleanup_sysctl(void) -{ - unregister_sysctl_table(sysctl_header); -} - -/* - * Now all the various file operations that we export. - */ - -static ssize_t rtc_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ -#ifndef RTC_IRQ - return -EIO; -#else - DECLARE_WAITQUEUE(wait, current); - unsigned long data; - ssize_t retval; - - if (rtc_has_irq == 0) - return -EIO; - - /* - * Historically this function used to assume that sizeof(unsigned long) - * is the same in userspace and kernelspace. This lead to problems - * for configurations with multiple ABIs such a the MIPS o32 and 64 - * ABIs supported on the same kernel. So now we support read of both - * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the - * userspace ABI. - */ - if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) - return -EINVAL; - - add_wait_queue(&rtc_wait, &wait); - - do { - /* First make it right. Then make it fast. Putting this whole - * block within the parentheses of a while would be too - * confusing. And no, xchg() is not the answer. */ - - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq (&rtc_lock); - data = rtc_irq_data; - rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); - - if (data != 0) - break; - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - goto out; - } - schedule(); - } while (1); - - if (count == sizeof(unsigned int)) - retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); - else - retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long); - if (!retval) - retval = count; - out: - current->state = TASK_RUNNING; - remove_wait_queue(&rtc_wait, &wait); - - return retval; -#endif -} - -static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) -{ - struct rtc_time wtime; - -#ifdef RTC_IRQ - if (rtc_has_irq == 0) { - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - case RTC_PIE_OFF: - case RTC_PIE_ON: - case RTC_UIE_OFF: - case RTC_UIE_ON: - case RTC_IRQP_READ: - case RTC_IRQP_SET: - return -EINVAL; - }; - } -#endif - - switch (cmd) { -#ifdef RTC_IRQ - case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ - { - mask_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_AIE_ON: /* Allow alarm interrupts. */ - { - set_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ - { - unsigned long flags; /* can be called from isr via rtc_control() */ - spin_lock_irqsave (&rtc_lock, flags); - mask_rtc_irq_bit_locked(RTC_PIE); - if (rtc_status & RTC_TIMER_ON) { - rtc_status &= ~RTC_TIMER_ON; - del_timer(&rtc_irq_timer); - } - spin_unlock_irqrestore (&rtc_lock, flags); - return 0; - } - case RTC_PIE_ON: /* Allow periodic ints */ - { - unsigned long flags; /* can be called from isr via rtc_control() */ - /* - * We don't really want Joe User enabling more - * than 64Hz of interrupts on a multi-user machine. - */ - if (!kernel && (rtc_freq > rtc_max_user_freq) && - (!capable(CAP_SYS_RESOURCE))) - return -EACCES; - - spin_lock_irqsave (&rtc_lock, flags); - if (!(rtc_status & RTC_TIMER_ON)) { - rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; - add_timer(&rtc_irq_timer); - rtc_status |= RTC_TIMER_ON; - } - set_rtc_irq_bit_locked(RTC_PIE); - spin_unlock_irqrestore (&rtc_lock, flags); - return 0; - } - case RTC_UIE_OFF: /* Mask ints from RTC updates. */ - { - mask_rtc_irq_bit(RTC_UIE); - return 0; - } - case RTC_UIE_ON: /* Allow ints for RTC updates. */ - { - set_rtc_irq_bit(RTC_UIE); - return 0; - } -#endif - case RTC_ALM_READ: /* Read the present alarm time */ - { - /* - * This returns a struct rtc_time. Reading >= 0xc0 - * means "don't care" or "match all". Only the tm_hour, - * tm_min, and tm_sec values are filled in. - */ - memset(&wtime, 0, sizeof(struct rtc_time)); - get_rtc_alm_time(&wtime); - break; - } - case RTC_ALM_SET: /* Store a time into the alarm */ - { - /* - * This expects a struct rtc_time. Writing 0xff means - * "don't care" or "match all". Only the tm_hour, - * tm_min and tm_sec are used. - */ - unsigned char hrs, min, sec; - struct rtc_time alm_tm; - - if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - hrs = alm_tm.tm_hour; - min = alm_tm.tm_min; - sec = alm_tm.tm_sec; - - spin_lock_irq(&rtc_lock); - if (hpet_set_alarm_time(hrs, min, sec)) { - /* - * Fallthru and set alarm time in CMOS too, - * so that we will get proper value in RTC_ALM_READ - */ - } - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - if (sec < 60) BIN_TO_BCD(sec); - else sec = 0xff; - - if (min < 60) BIN_TO_BCD(min); - else min = 0xff; - - if (hrs < 24) BIN_TO_BCD(hrs); - else hrs = 0xff; - } - CMOS_WRITE(hrs, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - spin_unlock_irq(&rtc_lock); - - return 0; - } - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - memset(&wtime, 0, sizeof(struct rtc_time)); - rtc_get_rtc_time(&wtime); - break; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; - unsigned int yrs; -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_yrs; -#endif - - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= epoch) > 255) /* They are unsigned */ - return -EINVAL; - - spin_lock_irq(&rtc_lock); -#ifdef CONFIG_MACH_DECSTATION - real_yrs = yrs; - yrs = 72; - - /* - * We want to keep the year set to 73 until March - * for non-leap years, so that Feb, 29th is handled - * correctly. - */ - if (!leap_yr && mon < 3) { - real_yrs--; - yrs = 73; - } -#endif - /* These limits and adjustments are independent of - * whether the chip is in binary mode or not. - */ - if (yrs > 169) { - spin_unlock_irq(&rtc_lock); - return -EINVAL; - } - if (yrs >= 100) - yrs -= 100; - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - } - - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - -#ifdef CONFIG_MACH_DECSTATION - CMOS_WRITE(real_yrs, RTC_DEC_YEAR); -#endif - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock_irq(&rtc_lock); - return 0; - } -#ifdef RTC_IRQ - case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ - { - return put_user(rtc_freq, (unsigned long __user *)arg); - } - case RTC_IRQP_SET: /* Set periodic IRQ rate. */ - { - int tmp = 0; - unsigned char val; - unsigned long flags; /* can be called from isr via rtc_control() */ - - /* - * The max we can do is 8192Hz. - */ - if ((arg < 2) || (arg > 8192)) - return -EINVAL; - /* - * We don't really want Joe User generating more - * than 64Hz of interrupts on a multi-user machine. - */ - if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) - return -EACCES; - - while (arg > (1<f_flags & FASYNC) { - rtc_fasync (-1, file, 0); - } -no_irq: -#endif - - spin_lock_irq (&rtc_lock); - rtc_irq_data = 0; - rtc_status &= ~RTC_IS_OPEN; - spin_unlock_irq (&rtc_lock); - return 0; -} - -#ifdef RTC_IRQ -/* Called without the kernel lock - fine */ -static unsigned int rtc_poll(struct file *file, poll_table *wait) -{ - unsigned long l; - - if (rtc_has_irq == 0) - return 0; - - poll_wait(file, &rtc_wait, wait); - - spin_lock_irq (&rtc_lock); - l = rtc_irq_data; - spin_unlock_irq (&rtc_lock); - - if (l != 0) - return POLLIN | POLLRDNORM; - return 0; -} -#endif - -/* - * exported stuffs - */ - -EXPORT_SYMBOL(rtc_register); -EXPORT_SYMBOL(rtc_unregister); -EXPORT_SYMBOL(rtc_control); - -int rtc_register(rtc_task_t *task) -{ -#ifndef RTC_IRQ - return -EIO; -#else - if (task == NULL || task->func == NULL) - return -EINVAL; - spin_lock_irq(&rtc_lock); - if (rtc_status & RTC_IS_OPEN) { - spin_unlock_irq(&rtc_lock); - return -EBUSY; - } - spin_lock(&rtc_task_lock); - if (rtc_callback) { - spin_unlock(&rtc_task_lock); - spin_unlock_irq(&rtc_lock); - return -EBUSY; - } - rtc_status |= RTC_IS_OPEN; - rtc_callback = task; - spin_unlock(&rtc_task_lock); - spin_unlock_irq(&rtc_lock); - return 0; -#endif -} - -int rtc_unregister(rtc_task_t *task) -{ -#ifndef RTC_IRQ - return -EIO; -#else - unsigned char tmp; - - spin_lock_irq(&rtc_lock); - spin_lock(&rtc_task_lock); - if (rtc_callback != task) { - spin_unlock(&rtc_task_lock); - spin_unlock_irq(&rtc_lock); - return -ENXIO; - } - rtc_callback = NULL; - - /* disable controls */ - if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { - tmp = CMOS_READ(RTC_CONTROL); - tmp &= ~RTC_PIE; - tmp &= ~RTC_AIE; - tmp &= ~RTC_UIE; - CMOS_WRITE(tmp, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - } - if (rtc_status & RTC_TIMER_ON) { - rtc_status &= ~RTC_TIMER_ON; - del_timer(&rtc_irq_timer); - } - rtc_status &= ~RTC_IS_OPEN; - spin_unlock(&rtc_task_lock); - spin_unlock_irq(&rtc_lock); - return 0; -#endif -} - -int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) -{ -#ifndef RTC_IRQ - return -EIO; -#else - unsigned long flags; - if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) - return -EINVAL; - spin_lock_irqsave(&rtc_task_lock, flags); - if (rtc_callback != task) { - spin_unlock_irqrestore(&rtc_task_lock, flags); - return -ENXIO; - } - spin_unlock_irqrestore(&rtc_task_lock, flags); - return rtc_do_ioctl(cmd, arg, 1); -#endif -} - - -/* - * The various file operations we support. - */ - -static const struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = rtc_read, -#ifdef RTC_IRQ - .poll = rtc_poll, -#endif - .ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, - .fasync = rtc_fasync, -}; - -static struct miscdevice rtc_dev = { - .minor = RTC_MINOR, - .name = "rtc", - .fops = &rtc_fops, -}; - -static const struct file_operations rtc_proc_fops = { - .owner = THIS_MODULE, - .open = rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#if defined(RTC_IRQ) && !defined(__sparc__) -static irq_handler_t rtc_int_handler_ptr; -#endif - -static int __init rtc_init(void) -{ - struct proc_dir_entry *ent; -#if defined(__alpha__) || defined(__mips__) - unsigned int year, ctrl; - char *guess = NULL; -#endif -#ifdef __sparc__ - struct linux_ebus *ebus; - struct linux_ebus_device *edev; -#ifdef __sparc_v9__ - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif -#endif -#ifndef __sparc__ - void *r; -#endif - -#ifdef __sparc__ - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_node->name, "rtc") == 0) { - rtc_port = edev->resource[0].start; - rtc_irq = edev->irqs[0]; - goto found; - } - } - } -#ifdef __sparc_v9__ - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { - rtc_port = isa_dev->resource.start; - rtc_irq = isa_dev->irq; - goto found; - } - } - } -#endif - printk(KERN_ERR "rtc_init: no PC rtc found\n"); - return -EIO; - -found: - if (rtc_irq == PCI_IRQ_NONE) { - rtc_has_irq = 0; - goto no_irq; - } - - /* - * XXX Interrupt pin #7 in Espresso is shared between RTC and - * PCI Slot 2 INTA# (and some INTx# in Slot 1). - */ - if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) { - printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); - return -EIO; - } -no_irq: -#else - if (RTC_IOMAPPED) - r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); - else - r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); - if (!r) { - printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", - (long)(RTC_PORT(0))); - return -EIO; - } - -#ifdef RTC_IRQ - if (is_hpet_enabled()) { - rtc_int_handler_ptr = hpet_rtc_interrupt; - } else { - rtc_int_handler_ptr = rtc_interrupt; - } - - if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) { - /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ - printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); - if (RTC_IOMAPPED) - release_region(RTC_PORT(0), RTC_IO_EXTENT); - else - release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); - return -EIO; - } - hpet_rtc_timer_init(); - -#endif - -#endif /* __sparc__ vs. others */ - - if (misc_register(&rtc_dev)) { -#ifdef RTC_IRQ - free_irq(RTC_IRQ, NULL); -#endif - release_region(RTC_PORT(0), RTC_IO_EXTENT); - return -ENODEV; - } - - ent = create_proc_entry("driver/rtc", 0, NULL); - if (!ent) { -#ifdef RTC_IRQ - free_irq(RTC_IRQ, NULL); -#endif - release_region(RTC_PORT(0), RTC_IO_EXTENT); - misc_deregister(&rtc_dev); - return -ENOMEM; - } - ent->proc_fops = &rtc_proc_fops; - -#if defined(__alpha__) || defined(__mips__) - rtc_freq = HZ; - - /* Each operating system on an Alpha uses its own epoch. - Let's try to guess which one we are using now. */ - - if (rtc_is_updating() != 0) - msleep(20); - - spin_lock_irq(&rtc_lock); - year = CMOS_READ(RTC_YEAR); - ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); - - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - BCD_TO_BIN(year); /* This should never happen... */ - - if (year < 20) { - epoch = 2000; - guess = "SRM (post-2000)"; - } else if (year >= 20 && year < 48) { - epoch = 1980; - guess = "ARC console"; - } else if (year >= 48 && year < 72) { - epoch = 1952; - guess = "Digital UNIX"; -#if defined(__mips__) - } else if (year >= 72 && year < 74) { - epoch = 2000; - guess = "Digital DECstation"; -#else - } else if (year >= 70) { - epoch = 1900; - guess = "Standard PC (1900)"; -#endif - } - if (guess) - printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); -#endif -#ifdef RTC_IRQ - if (rtc_has_irq == 0) - goto no_irq2; - - init_timer(&rtc_irq_timer); - rtc_irq_timer.function = rtc_dropped_irq; - spin_lock_irq(&rtc_lock); - rtc_freq = 1024; - if (!hpet_set_periodic_freq(rtc_freq)) { - /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ - CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); - } - spin_unlock_irq(&rtc_lock); -no_irq2: -#endif - - (void) init_sysctl(); - - printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); - - return 0; -} - -static void __exit rtc_exit (void) -{ - cleanup_sysctl(); - remove_proc_entry ("driver/rtc", NULL); - misc_deregister(&rtc_dev); - -#ifdef __sparc__ - if (rtc_has_irq) - free_irq (rtc_irq, &rtc_port); -#else - if (RTC_IOMAPPED) - release_region(RTC_PORT(0), RTC_IO_EXTENT); - else - release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); -#ifdef RTC_IRQ - if (rtc_has_irq) - free_irq (RTC_IRQ, NULL); -#endif -#endif /* __sparc__ */ -} - -module_init(rtc_init); -module_exit(rtc_exit); - -#ifdef RTC_IRQ -/* - * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. - * (usually during an IDE disk interrupt, with IRQ unmasking off) - * Since the interrupt handler doesn't get called, the IRQ status - * byte doesn't get read, and the RTC stops generating interrupts. - * A timer is set, and will call this function if/when that happens. - * To get it out of this stalled state, we just read the status. - * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. - * (You *really* shouldn't be trying to use a non-realtime system - * for something that requires a steady > 1KHz signal anyways.) - */ - -static void rtc_dropped_irq(unsigned long data) -{ - unsigned long freq; - - spin_lock_irq (&rtc_lock); - - if (hpet_rtc_dropped_irq()) { - spin_unlock_irq(&rtc_lock); - return; - } - - /* Just in case someone disabled the timer from behind our back... */ - if (rtc_status & RTC_TIMER_ON) - mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - - rtc_irq_data += ((rtc_freq/HZ)<<8); - rtc_irq_data &= ~0xff; - rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ - - freq = rtc_freq; - - spin_unlock_irq(&rtc_lock); - - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); - - /* Now we have new data */ - wake_up_interruptible(&rtc_wait); - - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); -} -#endif - -/* - * Info exported via "/proc/driver/rtc". - */ - -static int rtc_proc_show(struct seq_file *seq, void *v) -{ -#define YN(bit) ((ctrl & bit) ? "yes" : "no") -#define NY(bit) ((ctrl & bit) ? "no" : "yes") - struct rtc_time tm; - unsigned char batt, ctrl; - unsigned long freq; - - spin_lock_irq(&rtc_lock); - batt = CMOS_READ(RTC_VALID) & RTC_VRT; - ctrl = CMOS_READ(RTC_CONTROL); - freq = rtc_freq; - spin_unlock_irq(&rtc_lock); - - - rtc_get_rtc_time(&tm); - - /* - * There is no way to tell if the luser has the RTC set for local - * time or for Universal Standard Time (GMT). Probably local though. - */ - seq_printf(seq, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" - "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); - - get_rtc_alm_time(&tm); - - /* - * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will - * match any value for that particular field. Values that are - * greater than a valid time, but less than 0xc0 shouldn't appear. - */ - seq_puts(seq, "alarm\t\t: "); - if (tm.tm_hour <= 24) - seq_printf(seq, "%02d:", tm.tm_hour); - else - seq_puts(seq, "**:"); - - if (tm.tm_min <= 59) - seq_printf(seq, "%02d:", tm.tm_min); - else - seq_puts(seq, "**:"); - - if (tm.tm_sec <= 59) - seq_printf(seq, "%02d\n", tm.tm_sec); - else - seq_puts(seq, "**\n"); - - seq_printf(seq, - "DST_enable\t: %s\n" - "BCD\t\t: %s\n" - "24hr\t\t: %s\n" - "square_wave\t: %s\n" - "alarm_IRQ\t: %s\n" - "update_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n" - "periodic_freq\t: %ld\n" - "batt_status\t: %s\n", - YN(RTC_DST_EN), - NY(RTC_DM_BINARY), - YN(RTC_24H), - YN(RTC_SQWE), - YN(RTC_AIE), - YN(RTC_UIE), - YN(RTC_PIE), - freq, - batt ? "okay" : "dead"); - - return 0; -#undef YN -#undef NY -} - -static int rtc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, rtc_proc_show, NULL); -} - -void rtc_get_rtc_time(struct rtc_time *rtc_tm) -{ - unsigned long uip_watchdog = jiffies, flags; - unsigned char ctrl; -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_year; -#endif - - /* - * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 20ms. There is no need to - * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. - * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then - * immediately read /dev/rtc which will block until you get the IRQ. - * Once the read clears, read the RTC time (again via ioctl). Easy. - */ - - while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) - cpu_relax(); - - /* - * Only the values that we read from the RTC are set. We leave - * tm_wday, tm_yday and tm_isdst untouched. Note that while the - * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is - * only updated by the RTC when initially set to a non-zero value. - */ - spin_lock_irqsave(&rtc_lock, flags); - rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); - rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); - rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); - rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); - rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); - rtc_tm->tm_year = CMOS_READ(RTC_YEAR); - /* Only set from 2.6.16 onwards */ - rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); - -#ifdef CONFIG_MACH_DECSTATION - real_year = CMOS_READ(RTC_DEC_YEAR); -#endif - ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irqrestore(&rtc_lock, flags); - - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(rtc_tm->tm_sec); - BCD_TO_BIN(rtc_tm->tm_min); - BCD_TO_BIN(rtc_tm->tm_hour); - BCD_TO_BIN(rtc_tm->tm_mday); - BCD_TO_BIN(rtc_tm->tm_mon); - BCD_TO_BIN(rtc_tm->tm_year); - BCD_TO_BIN(rtc_tm->tm_wday); - } - -#ifdef CONFIG_MACH_DECSTATION - rtc_tm->tm_year += real_year - 72; -#endif - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) - rtc_tm->tm_year += 100; - - rtc_tm->tm_mon--; -} - -static void get_rtc_alm_time(struct rtc_time *alm_tm) -{ - unsigned char ctrl; - - /* - * Only the values that we read from the RTC are set. That - * means only tm_hour, tm_min, and tm_sec. - */ - spin_lock_irq(&rtc_lock); - alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); - alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); - alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); - ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); - - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(alm_tm->tm_sec); - BCD_TO_BIN(alm_tm->tm_min); - BCD_TO_BIN(alm_tm->tm_hour); - } -} - -#ifdef RTC_IRQ -/* - * Used to disable/enable interrupts for any one of UIE, AIE, PIE. - * Rumour has it that if you frob the interrupt enable/disable - * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to - * ensure you actually start getting interrupts. Probably for - * compatibility with older/broken chipset RTC implementations. - * We also clear out any old irq data after an ioctl() that - * meddles with the interrupt enable/disable bits. - */ - -static void mask_rtc_irq_bit_locked(unsigned char bit) -{ - unsigned char val; - - if (hpet_mask_rtc_irq_bit(bit)) - return; - val = CMOS_READ(RTC_CONTROL); - val &= ~bit; - CMOS_WRITE(val, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - - rtc_irq_data = 0; -} - -static void set_rtc_irq_bit_locked(unsigned char bit) -{ - unsigned char val; - - if (hpet_set_rtc_irq_bit(bit)) - return; - val = CMOS_READ(RTC_CONTROL); - val |= bit; - CMOS_WRITE(val, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - - rtc_irq_data = 0; -} -#endif - -MODULE_AUTHOR("Paul Gortmaker"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(RTC_MINOR); +/* + * A simple generic Real Time Clock interface for Linux/Moxa R7000 + * + * History: + * Date Author Comment + * 11-27-2003 Victor Yu. Create it. + * 01-26-2006 Jimmy_chen@moxa.com.tw Copy UC7420 RTC and fix it to meet MOXART + * 02-09-2007 Victor Yu. Porting to kernel 2.6.19. Interrupt kernel API changed. + * 09-05-2007 Victor Yu. Change to use raw level gpio API. + */ + +#define RTC_VERSION "1.0" + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_ARCH_EM1240) || defined(CONFIG_ARCH_EM1240_IVTC) || defined(CONFIG_ARCH_EM1240_MT) +#define GPIO_RTC_SCLK (1<<20) /* GPIO5 */ +#define GPIO_RTC_DATA (1<<21) /* GPIO6 */ +#define GPIO_RTC_RESET (1<<9) /* GPIO7 */ +#elif defined(CONFIG_ARCH_W311_TEST) // add by Victor Yu. 07-06-2008 +#define GPIO_RTC_SCLK (1<<24) /* GPIO5 */ +#define GPIO_RTC_DATA (1<<25) /* GPIO6 */ +#define GPIO_RTC_RESET (1<<26) /* GPIO7 */ +#else +#define GPIO_RTC_SCLK (1<<5) /* GPIO5 */ +#define GPIO_RTC_DATA (1<<6) /* GPIO6 */ +#define GPIO_RTC_RESET (1<<7) /* GPIO7 */ +#endif +#define GPIO_RTC_MASK (GPIO_RTC_SCLK|GPIO_RTC_DATA|GPIO_RTC_RESET) +#define MOXA_GPIO_PPENABLE 0x18 +#define MOXA_GPIO_PPTYPE 0x1C +#define MOXA_GPIO_DATAOUT 0x0 +#define MOXA_GPIO_DATAIN 0x04 +#define MOXA_GPIO_PINDIR 0x08 +#define GPIO_PINDIR_HIGH 1 +#define GPIO_PINDIR_LOW 0 +#define EM1240_GPIO_HIGH 1 +#define EM1240_GPIO_LOW 0 +#define RTC_PROTECT_W 0x8E +#define RTC_PROTECT_R 0x8F +#define RTC_YEAR_W 0x8C +#define RTC_YEAR_R 0x8D +#define RTC_DAY_W 0x8A +#define RTC_DAY_R 0x8B +#define RTC_MONTH_W 0x88 +#define RTC_MONTH_R 0x89 +#define RTC_DATE_W 0x86 +#define RTC_DATE_R 0x87 +#define RTC_HOURS_W 0x84 +#define RTC_HOURS_R 0x85 +#define RTC_MINUTES_W 0x82 +#define RTC_MINUTES_R 0x83 +#define RTC_SECONDS_W 0x80 +#define RTC_SECONDS_R 0x81 +#define RTC_DELAY_TIME 8 // 8 usecond +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define PIO(x) 1< KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + /* write command byte */ + for ( i=0; i<8; i++, Cmd>>=1 ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Cmd & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW); + /* read data byte */ + udelay(RTC_DELAY_TIME); + for ( i=0,data=0; i<8; i++ ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + gpio_line_get(GPIO_RTC_DATA, &v); + if ( v ) + data |= (1< KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif + + return data; +} + +static void RTCWriteRegister(u8 Cmd, u8 Data) +{ + int i; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + /* write command byte */ + for ( i=0; i<8; i++,Cmd>>=1 ) { + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Cmd & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + + /* write data byte */ + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + for ( i=0; i<8; i++,Data>>=1 ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Data & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif +} + +#if 1 // add by Victor Yu. 01-10-2005 +static int day_of_year[12]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +#endif +static void get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char v; + + spin_lock_irq(&rtc_lock); + v = RTCReadRegister(RTC_SECONDS_R); + rtc_tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_MINUTES_R); + rtc_tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_HOURS_R); + if ( v & 0x80 ) { // 12-hour mode + rtc_tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if ( v & 0x20 ) { // PM mode + rtc_tm->tm_hour += 12; + if ( rtc_tm->tm_hour >= 24 ) + rtc_tm->tm_hour = 0; + } + } else { // 24-hour mode + rtc_tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + v = RTCReadRegister(RTC_DATE_R); + rtc_tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_MONTH_R); + rtc_tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + rtc_tm->tm_mon--; + v = RTCReadRegister(RTC_YEAR_R); + rtc_tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += 100; +#if 1 // add by Victor Yu. 01-10-2005 + v = RTCReadRegister(RTC_DAY_R); + rtc_tm->tm_wday = (v & 0x0f) - 1; + rtc_tm->tm_yday = day_of_year[rtc_tm->tm_mon]; + rtc_tm->tm_yday += (rtc_tm->tm_mday-1); + if ( rtc_tm->tm_mon >= 2 ) { + if ( !(rtc_tm->tm_year % 4) && (rtc_tm->tm_year % 100) ) + rtc_tm->tm_yday++; + } + rtc_tm->tm_isdst = 0; +#endif + spin_unlock_irq(&rtc_lock); +} + +static int +rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + unsigned char v; + + switch (cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + get_rtc_time(&rtc_tm); + return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ? + -EFAULT : 0; + case RTC_SET_TIME: /* Set the RTC */ + { + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, + (struct rtc_time *) arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + spin_lock_irq(&rtc_lock); + /* These limits and adjustments are independant of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irq(&rtc_lock); + return -EINVAL; + } + if (yrs >= 100) + yrs -= 100; + + RTCWriteRegister(RTC_PROTECT_W, 0); + v = ((hrs / 10) << 4) | (hrs % 10); + RTCWriteRegister(RTC_HOURS_W, v); + v = ((min / 10) << 4) | (min % 10); + RTCWriteRegister(RTC_MINUTES_W, v); + v = ((sec / 10) << 4) | (sec % 10); + RTCWriteRegister(RTC_SECONDS_W, v); + v = ((yrs / 10) << 4) | (yrs % 10); + RTCWriteRegister(RTC_YEAR_W, v); + v = ((mon / 10) << 4) | (mon % 10); + RTCWriteRegister(RTC_MONTH_W, v); + v = ((day / 10) << 4) | (day % 10); + RTCWriteRegister(RTC_DATE_W, v); + RTCWriteRegister(RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&rtc_lock); + return 0; + } + default: + return -EINVAL; + } +} + +/* We use rtc_lock to protect against concurrent opens. So the BKL is not + * needed here. Or anywhere else in this driver. */ +static int rtc_open(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + + rtc_status |= RTC_IS_OPEN; + + spin_unlock_irq(&rtc_lock); + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq(&rtc_lock); + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + ioctl:rtc_ioctl, + open:rtc_open, + release:rtc_release, +}; + +static struct miscdevice rtc_dev = { + RTC_MINOR, + "rtc", + &rtc_fops +}; + +#define PMU_GPIO_ON 0xdfc003f0 +static int __init rtc_init(void) +{ + struct rtc_time rtc_tm; + + mcpu_gpio_mp_set(GPIO_RTC_MASK); + gpio_line_inout(GPIO_RTC_RESET, GPIO_PINDIR_HIGH); + gpio_line_inout(GPIO_RTC_SCLK, GPIO_PINDIR_HIGH); + +#if 1 // add by Victor Yu. 04-21-2005, to avoid the RTS stop + get_rtc_time(&rtc_tm); +//printk("YYYY-MON-DAY-HH-MM-SS=%d-%d-%d-%d-%d-%d\n", rtc_tm.tm_year, rtc_tm.tm_mon, rtc_tm.tm_mday, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + if ( rtc_tm.tm_sec == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_hour == 0 && rtc_tm.tm_year == 100 && rtc_tm.tm_mon == 0 && rtc_tm.tm_mday == 1 ) { + printk("The RTC has stoped. Now reenable it.\n"); + RTCWriteRegister(RTC_PROTECT_W,0);/* Disable Write Protect */ + RTCWriteRegister(RTC_SECONDS_W,0);/* Enable OSC */ + RTCWriteRegister(RTC_PROTECT_W,0x80);/* Enable Write Protect */ + } +#endif + misc_register(&rtc_dev); + create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc, NULL); + + printk(KERN_INFO "Generic Moxa RTC Driver v" RTC_VERSION "\n"); + return 0; +} + +static void __exit rtc_exit(void) +{ + remove_proc_entry("driver/rtc", NULL); + misc_deregister(&rtc_dev); + +} + +module_init(rtc_init); +module_exit(rtc_exit); + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_output(char *buf) +{ + char *p; + struct rtc_time tm; + + get_rtc_time(&tm); + + p = buf; + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_proc_output(page); + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/rtc.c-bak-09052007 b/drivers/char/rtc.c-bak-09052007 new file mode 100644 index 00000000..3bdc7e2d --- /dev/null +++ b/drivers/char/rtc.c-bak-09052007 @@ -0,0 +1,461 @@ +/* + * A simple generic Real Time Clock interface for Linux/Moxa R7000 + * + * History: + * Date Author Comment + * 11-27-2003 Victor Yu. Create it. + * 01-26-2006 Jimmy_chen@moxa.com.tw Copy UC7420 RTC and fix it to meet MOXART + * 02-09-2007 Victor Yu. Porting to kernel 2.6.19. Interrupt kernel API changed. + * 09-05-2007 Victor Yu. Change to use raw level gpio API. + */ + +#define RTC_VERSION "1.0" + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_ARCH_EM1240) || defined(CONFIG_ARCH_EM1240_IVTC) || defined(CONFIG_ARCH_EM1240_MT) +#define GPIO_RTC_SCLK (1<<20) /* GPIO5 */ +#define GPIO_RTC_DATA (1<<21) /* GPIO6 */ +#define GPIO_RTC_RESET (1<<9) /* GPIO7 */ +#else +#define GPIO_RTC_SCLK (1<<5) /* GPIO5 */ +#define GPIO_RTC_DATA (1<<6) /* GPIO6 */ +#define GPIO_RTC_RESET (1<<7) /* GPIO7 */ +#endif +#define GPIO_RTC_MASK (GPIO_RTC_SCLK|GPIO_RTC_DATA|GPIO_RTC_RESET) +#define MOXA_GPIO_PPENABLE 0x18 +#define MOXA_GPIO_PPTYPE 0x1C +#define MOXA_GPIO_DATAOUT 0x0 +#define MOXA_GPIO_DATAIN 0x04 +#define MOXA_GPIO_PINDIR 0x08 +#define GPIO_PINDIR_HIGH 1 +#define GPIO_PINDIR_LOW 0 +#define EM1240_GPIO_HIGH 1 +#define EM1240_GPIO_LOW 0 +#define RTC_PROTECT_W 0x8E +#define RTC_PROTECT_R 0x8F +#define RTC_YEAR_W 0x8C +#define RTC_YEAR_R 0x8D +#define RTC_DAY_W 0x8A +#define RTC_DAY_R 0x8B +#define RTC_MONTH_W 0x88 +#define RTC_MONTH_R 0x89 +#define RTC_DATE_W 0x86 +#define RTC_DATE_R 0x87 +#define RTC_HOURS_W 0x84 +#define RTC_HOURS_R 0x85 +#define RTC_MINUTES_W 0x82 +#define RTC_MINUTES_R 0x83 +#define RTC_SECONDS_W 0x80 +#define RTC_SECONDS_R 0x81 +#define RTC_DELAY_TIME 8 // 8 usecond +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define PIO(x) 1< KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + /* write command byte */ + for ( i=0; i<8; i++, Cmd>>=1 ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Cmd & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW); + /* read data byte */ + udelay(RTC_DELAY_TIME); + for ( i=0,data=0; i<8; i++ ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + gpio_line_get(GPIO_RTC_DATA, &v); + if ( v ) + data |= (1< KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif + + return data; +} + +static void RTCWriteRegister(u8 Cmd, u8 Data) +{ + int i; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + /* write command byte */ + for ( i=0; i<8; i++,Cmd>>=1 ) { + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Cmd & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + + /* write data byte */ + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH); + for ( i=0; i<8; i++,Data>>=1 ){ + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + if ( Data & 1 ) + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH); + else + gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH); + udelay(RTC_DELAY_TIME); + } + gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW); + gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_LOW); + udelay(RTC_DELAY_TIME); + gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif +} + +#if 1 // add by Victor Yu. 01-10-2005 +static int day_of_year[12]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +#endif +static void get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char v; + + spin_lock_irq(&rtc_lock); + v = RTCReadRegister(RTC_SECONDS_R); + rtc_tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_MINUTES_R); + rtc_tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_HOURS_R); + if ( v & 0x80 ) { // 12-hour mode + rtc_tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if ( v & 0x20 ) { // PM mode + rtc_tm->tm_hour += 12; + if ( rtc_tm->tm_hour >= 24 ) + rtc_tm->tm_hour = 0; + } + } else { // 24-hour mode + rtc_tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + v = RTCReadRegister(RTC_DATE_R); + rtc_tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + v = RTCReadRegister(RTC_MONTH_R); + rtc_tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + rtc_tm->tm_mon--; + v = RTCReadRegister(RTC_YEAR_R); + rtc_tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += 100; +#if 1 // add by Victor Yu. 01-10-2005 + v = RTCReadRegister(RTC_DAY_R); + rtc_tm->tm_wday = (v & 0x0f) - 1; + rtc_tm->tm_yday = day_of_year[rtc_tm->tm_mon]; + rtc_tm->tm_yday += (rtc_tm->tm_mday-1); + if ( rtc_tm->tm_mon >= 2 ) { + if ( !(rtc_tm->tm_year % 4) && (rtc_tm->tm_year % 100) ) + rtc_tm->tm_yday++; + } + rtc_tm->tm_isdst = 0; +#endif + spin_unlock_irq(&rtc_lock); +} + +static int +rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + unsigned char v; + + switch (cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + get_rtc_time(&rtc_tm); + return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ? + -EFAULT : 0; + case RTC_SET_TIME: /* Set the RTC */ + { + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, + (struct rtc_time *) arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + spin_lock_irq(&rtc_lock); + /* These limits and adjustments are independant of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irq(&rtc_lock); + return -EINVAL; + } + if (yrs >= 100) + yrs -= 100; + + RTCWriteRegister(RTC_PROTECT_W, 0); + v = ((hrs / 10) << 4) | (hrs % 10); + RTCWriteRegister(RTC_HOURS_W, v); + v = ((min / 10) << 4) | (min % 10); + RTCWriteRegister(RTC_MINUTES_W, v); + v = ((sec / 10) << 4) | (sec % 10); + RTCWriteRegister(RTC_SECONDS_W, v); + v = ((yrs / 10) << 4) | (yrs % 10); + RTCWriteRegister(RTC_YEAR_W, v); + v = ((mon / 10) << 4) | (mon % 10); + RTCWriteRegister(RTC_MONTH_W, v); + v = ((day / 10) << 4) | (day % 10); + RTCWriteRegister(RTC_DATE_W, v); + RTCWriteRegister(RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&rtc_lock); + return 0; + } + default: + return -EINVAL; + } +} + +/* We use rtc_lock to protect against concurrent opens. So the BKL is not + * needed here. Or anywhere else in this driver. */ +static int rtc_open(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + + rtc_status |= RTC_IS_OPEN; + + spin_unlock_irq(&rtc_lock); + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq(&rtc_lock); + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + ioctl:rtc_ioctl, + open:rtc_open, + release:rtc_release, +}; + +static struct miscdevice rtc_dev = { + RTC_MINOR, + "rtc", + &rtc_fops +}; + +#define PMU_GPIO_ON 0xdfc003f0 +static int __init rtc_init(void) +{ + struct rtc_time rtc_tm; + + //outw(inl(CPE_PMU_BASE+0x100)|PMU_GPIO_ON,CPE_PMU_BASE+0x100) ; + outl(inl(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)|(GPIO_RTC_SCLK|GPIO_RTC_DATA|GPIO_RTC_RESET),(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)) ; + mcpu_gpio_mp_set(GPIO_RTC_MASK); + gpio_line_inout(GPIO_RTC_RESET, GPIO_PINDIR_HIGH); + gpio_line_inout(GPIO_RTC_SCLK, GPIO_PINDIR_HIGH); + +#if 1 // add by Victor Yu. 04-21-2005, to avoid the RTS stop + get_rtc_time(&rtc_tm); +//printk("YYYY-MON-DAY-HH-MM-SS=%d-%d-%d-%d-%d-%d\n", rtc_tm.tm_year, rtc_tm.tm_mon, rtc_tm.tm_mday, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + if ( rtc_tm.tm_sec == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_hour == 0 && rtc_tm.tm_year == 100 && rtc_tm.tm_mon == 0 && rtc_tm.tm_mday == 1 ) { + printk("The RTC has stoped. Now reenable it.\n"); + RTCWriteRegister(RTC_PROTECT_W,0);/* Disable Write Protect */ + RTCWriteRegister(RTC_SECONDS_W,0);/* Enable OSC */ + RTCWriteRegister(RTC_PROTECT_W,0x80);/* Enable Write Protect */ + } +#endif + misc_register(&rtc_dev); + create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc, NULL); + + printk(KERN_INFO "Generic Moxa RTC Driver v" RTC_VERSION "\n"); + return 0; +} + +static void __exit rtc_exit(void) +{ + remove_proc_entry("driver/rtc", NULL); + misc_deregister(&rtc_dev); + +} + +module_init(rtc_init); +module_exit(rtc_exit); + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_output(char *buf) +{ + char *p; + struct rtc_time tm; + + get_rtc_time(&tm); + + p = buf; + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_proc_output(page); + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/rtc.c-old b/drivers/char/rtc.c-old new file mode 100644 index 00000000..ac48b086 --- /dev/null +++ b/drivers/char/rtc.c-old @@ -0,0 +1,1380 @@ +/* + * Real Time Clock interface for Linux + * + * Copyright (C) 1996 Paul Gortmaker + * + * This driver allows use of the real time clock (built into + * nearly all computers) from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the + * /proc/driver/rtc pseudo-file for status information. + * + * The ioctls can be used to set the interrupt behaviour and + * generation rate from the RTC via IRQ 8. Then the /dev/rtc + * interface can be used to make use of these timer interrupts, + * be they interval or alarm based. + * + * The /dev/rtc interface will block on reads until an interrupt + * has been received. If a RTC interrupt has already happened, + * it will output an unsigned long and then block. The output value + * contains the interrupt status in the low byte and the number of + * interrupts since the last read in the remaining high bytes. The + * /dev/rtc interface can also be used with the select(2) call. + * + * 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. + * + * Based on other minimal char device drivers, like Alan's + * watchdog, Ted's random, etc. etc. + * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * 1.09a Pete Zaitcev: Sun SPARC + * 1.09b Jeff Garzik: Modularize, init cleanup + * 1.09c Jeff Garzik: SMP cleanup + * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix + * 1.10c Cesar Barros: SMP locking fixes and cleanup + * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit + * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. + * 1.11 Takashi Iwai: Kernel access functions + * rtc_register/rtc_unregister/rtc_control + * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init + * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer + * CONFIG_HPET_EMULATE_RTC + * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. + * 1.12ac Alan Cox: Allow read access to the day of week register + */ + +#define RTC_VERSION "1.12ac" + +/* + * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with + * interrupts disabled. Due to the index-port/data-port (0x70/0x71) + * design of the RTC, we don't want two different things trying to + * get to it at once. (e.g. the periodic 11 min sync from time.c vs. + * this driver.) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(__i386__) +#include +#endif + +#ifdef __sparc__ +#include +#include +#ifdef __sparc_v9__ +#include +#endif + +static unsigned long rtc_port; +static int rtc_irq = PCI_IRQ_NONE; +#endif + +#ifdef CONFIG_HPET_RTC_IRQ +#undef RTC_IRQ +#endif + +#ifdef RTC_IRQ +static int rtc_has_irq = 1; +#else +#define rtc_has_irq 0 +#endif + +#ifndef CONFIG_HPET_EMULATE_RTC +#define is_hpet_enabled() 0 +#define hpet_set_alarm_time(hrs, min, sec) 0 +#define hpet_set_periodic_freq(arg) 0 +#define hpet_mask_rtc_irq_bit(arg) 0 +#define hpet_set_rtc_irq_bit(arg) 0 +#define hpet_rtc_timer_init() do { } while (0) +#define hpet_rtc_dropped_irq() 0 +static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;} +#else +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); +#endif + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static struct fasync_struct *rtc_async_queue; + +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); + +#ifdef RTC_IRQ +static struct timer_list rtc_irq_timer; +#endif + +static ssize_t rtc_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos); + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +#ifdef RTC_IRQ +static unsigned int rtc_poll(struct file *file, poll_table *wait); +#endif + +static void get_rtc_alm_time (struct rtc_time *alm_tm); +#ifdef RTC_IRQ +static void rtc_dropped_irq(unsigned long data); + +static void set_rtc_irq_bit_locked(unsigned char bit); +static void mask_rtc_irq_bit_locked(unsigned char bit); + +static inline void set_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + set_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} + +static void mask_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + mask_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} +#endif + +static int rtc_proc_open(struct inode *inode, struct file *file); + +/* + * Bits in rtc_status. (6 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define RTC_TIMER_ON 0x02 /* missed irq timer active */ + +/* + * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is + * protected by the big kernel lock. However, ioctl can still disable the timer + * in rtc_status and then with del_timer after the interrupt has read + * rtc_status but before mod_timer is called, which would then reenable the + * timer (but you would need to have an awful timing before you'd trip on it) + */ +static unsigned long rtc_status = 0; /* bitmapped status byte. */ +static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ +static unsigned long rtc_irq_data = 0; /* our output to the world */ +static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ + +#ifdef RTC_IRQ +/* + * rtc_task_lock nests inside rtc_lock. + */ +static DEFINE_SPINLOCK(rtc_task_lock); +static rtc_task_t *rtc_callback = NULL; +#endif + +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char rtc_is_updating(void) +{ + unsigned long flags; + unsigned char uip; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + +#ifdef RTC_IRQ +/* + * A very tiny interrupt handler. It runs with IRQF_DISABLED set, + * but there is possibility of conflicting with the set_rtc_mmss() + * call (the rtc irq and the timer irq can easily run at the same + * time in two different CPUs). So we need to serialize + * accesses to the chip with the rtc_lock spinlock that each + * architecture should implement in the timer code. + * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) + */ + +irqreturn_t rtc_interrupt(int irq, void *dev_id) +{ + /* + * Can be an alarm interrupt, update complete interrupt, + * or a periodic interrupt. We store the status in the + * low byte and the number of interrupts received since + * the last read in the remainder of rtc_irq_data. + */ + + spin_lock (&rtc_lock); + rtc_irq_data += 0x100; + rtc_irq_data &= ~0xff; + if (is_hpet_enabled()) { + /* + * In this case it is HPET RTC interrupt handler + * calling us, with the interrupt information + * passed as arg1, instead of irq. + */ + rtc_irq_data |= (unsigned long)irq & 0xF0; + } else { + rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); + } + + if (rtc_status & RTC_TIMER_ON) + mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); + + spin_unlock (&rtc_lock); + + /* Now do the rest of the actions */ + spin_lock(&rtc_task_lock); + if (rtc_callback) + rtc_callback->func(rtc_callback->private_data); + spin_unlock(&rtc_task_lock); + wake_up_interruptible(&rtc_wait); + + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + + return IRQ_HANDLED; +} +#endif + +/* + * sysctl-tuning infrastructure. + */ +static ctl_table rtc_table[] = { + { + .ctl_name = 1, + .procname = "max-user-freq", + .data = &rtc_max_user_freq, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } +}; + +static ctl_table rtc_root[] = { + { + .ctl_name = 1, + .procname = "rtc", + .maxlen = 0, + .mode = 0555, + .child = rtc_table, + }, + { .ctl_name = 0 } +}; + +static ctl_table dev_root[] = { + { + .ctl_name = CTL_DEV, + .procname = "dev", + .maxlen = 0, + .mode = 0555, + .child = rtc_root, + }, + { .ctl_name = 0 } +}; + +static struct ctl_table_header *sysctl_header; + +static int __init init_sysctl(void) +{ + sysctl_header = register_sysctl_table(dev_root, 0); + return 0; +} + +static void __exit cleanup_sysctl(void) +{ + unregister_sysctl_table(sysctl_header); +} + +/* + * Now all the various file operations that we export. + */ + +static ssize_t rtc_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ +#ifndef RTC_IRQ + return -EIO; +#else + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + + if (rtc_has_irq == 0) + return -EIO; + + /* + * Historically this function used to assume that sizeof(unsigned long) + * is the same in userspace and kernelspace. This lead to problems + * for configurations with multiple ABIs such a the MIPS o32 and 64 + * ABIs supported on the same kernel. So now we support read of both + * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the + * userspace ABI. + */ + if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc_wait, &wait); + + do { + /* First make it right. Then make it fast. Putting this whole + * block within the parentheses of a while would be too + * confusing. And no, xchg() is not the answer. */ + + __set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irq (&rtc_lock); + data = rtc_irq_data; + rtc_irq_data = 0; + spin_unlock_irq (&rtc_lock); + + if (data != 0) + break; + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + schedule(); + } while (1); + + if (count == sizeof(unsigned int)) + retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); + else + retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long); + if (!retval) + retval = count; + out: + current->state = TASK_RUNNING; + remove_wait_queue(&rtc_wait, &wait); + + return retval; +#endif +} + +static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) +{ + struct rtc_time wtime; + + if (rtc_has_irq == 0) { + switch (cmd) { + case RTC_AIE_OFF: + case RTC_AIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_IRQP_READ: + case RTC_IRQP_SET: + return -EINVAL; + }; + } + + switch (cmd) { +#ifdef RTC_IRQ + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + mask_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + set_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ + { + unsigned long flags; /* can be called from isr via rtc_control() */ + spin_lock_irqsave (&rtc_lock, flags); + mask_rtc_irq_bit_locked(RTC_PIE); + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + spin_unlock_irqrestore (&rtc_lock, flags); + return 0; + } + case RTC_PIE_ON: /* Allow periodic ints */ + { + unsigned long flags; /* can be called from isr via rtc_control() */ + /* + * We don't really want Joe User enabling more + * than 64Hz of interrupts on a multi-user machine. + */ + if (!kernel && (rtc_freq > rtc_max_user_freq) && + (!capable(CAP_SYS_RESOURCE))) + return -EACCES; + + spin_lock_irqsave (&rtc_lock, flags); + if (!(rtc_status & RTC_TIMER_ON)) { + rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; + add_timer(&rtc_irq_timer); + rtc_status |= RTC_TIMER_ON; + } + set_rtc_irq_bit_locked(RTC_PIE); + spin_unlock_irqrestore (&rtc_lock, flags); + return 0; + } + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + { + mask_rtc_irq_bit(RTC_UIE); + return 0; + } + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + { + set_rtc_irq_bit(RTC_UIE); + return 0; + } +#endif + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ + memset(&wtime, 0, sizeof(struct rtc_time)); + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + unsigned char hrs, min, sec; + struct rtc_time alm_tm; + + if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + + spin_lock_irq(&rtc_lock); + if (hpet_set_alarm_time(hrs, min, sec)) { + /* + * Fallthru and set alarm time in CMOS too, + * so that we will get proper value in RTC_ALM_READ + */ + } + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || + RTC_ALWAYS_BCD) + { + if (sec < 60) BIN_TO_BCD(sec); + else sec = 0xff; + + if (min < 60) BIN_TO_BCD(min); + else min = 0xff; + + if (hrs < 24) BIN_TO_BCD(hrs); + else hrs = 0xff; + } + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + spin_unlock_irq(&rtc_lock); + + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + memset(&wtime, 0, sizeof(struct rtc_time)); + rtc_get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_yrs; +#endif + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + spin_lock_irq(&rtc_lock); +#ifdef CONFIG_MACH_DECSTATION + real_yrs = yrs; + yrs = 72; + + /* + * We want to keep the year set to 73 until March + * for non-leap years, so that Feb, 29th is handled + * correctly. + */ + if (!leap_yr && mon < 3) { + real_yrs--; + yrs = 73; + } +#endif + /* These limits and adjustments are independent of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irq(&rtc_lock); + return -EINVAL; + } + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + +#ifdef CONFIG_MACH_DECSTATION + CMOS_WRITE(real_yrs, RTC_DEC_YEAR); +#endif + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + spin_unlock_irq(&rtc_lock); + return 0; + } +#ifdef RTC_IRQ + case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ + { + return put_user(rtc_freq, (unsigned long __user *)arg); + } + case RTC_IRQP_SET: /* Set periodic IRQ rate. */ + { + int tmp = 0; + unsigned char val; + unsigned long flags; /* can be called from isr via rtc_control() */ + + /* + * The max we can do is 8192Hz. + */ + if ((arg < 2) || (arg > 8192)) + return -EINVAL; + /* + * We don't really want Joe User generating more + * than 64Hz of interrupts on a multi-user machine. + */ + if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + return -EACCES; + + while (arg > (1<f_flags & FASYNC) { + rtc_fasync (-1, file, 0); + } +no_irq: +#endif + + spin_lock_irq (&rtc_lock); + rtc_irq_data = 0; + rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq (&rtc_lock); + return 0; +} + +#ifdef RTC_IRQ +/* Called without the kernel lock - fine */ +static unsigned int rtc_poll(struct file *file, poll_table *wait) +{ + unsigned long l; + + if (rtc_has_irq == 0) + return 0; + + poll_wait(file, &rtc_wait, wait); + + spin_lock_irq (&rtc_lock); + l = rtc_irq_data; + spin_unlock_irq (&rtc_lock); + + if (l != 0) + return POLLIN | POLLRDNORM; + return 0; +} +#endif + +/* + * exported stuffs + */ + +EXPORT_SYMBOL(rtc_register); +EXPORT_SYMBOL(rtc_unregister); +EXPORT_SYMBOL(rtc_control); + +int rtc_register(rtc_task_t *task) +{ +#ifndef RTC_IRQ + return -EIO; +#else + if (task == NULL || task->func == NULL) + return -EINVAL; + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + spin_lock(&rtc_task_lock); + if (rtc_callback) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + rtc_status |= RTC_IS_OPEN; + rtc_callback = task; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_unregister(rtc_task_t *task) +{ +#ifndef RTC_IRQ + return -EIO; +#else + unsigned char tmp; + + spin_lock_irq(&rtc_lock); + spin_lock(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -ENXIO; + } + rtc_callback = NULL; + + /* disable controls */ + if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { + tmp = CMOS_READ(RTC_CONTROL); + tmp &= ~RTC_PIE; + tmp &= ~RTC_AIE; + tmp &= ~RTC_UIE; + CMOS_WRITE(tmp, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + } + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + rtc_status &= ~RTC_IS_OPEN; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) +{ +#ifndef RTC_IRQ + return -EIO; +#else + unsigned long flags; + if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) + return -EINVAL; + spin_lock_irqsave(&rtc_task_lock, flags); + if (rtc_callback != task) { + spin_unlock_irqrestore(&rtc_task_lock, flags); + return -ENXIO; + } + spin_unlock_irqrestore(&rtc_task_lock, flags); + return rtc_do_ioctl(cmd, arg, 1); +#endif +} + + +/* + * The various file operations we support. + */ + +static const struct file_operations rtc_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = rtc_read, +#ifdef RTC_IRQ + .poll = rtc_poll, +#endif + .ioctl = rtc_ioctl, + .open = rtc_open, + .release = rtc_release, + .fasync = rtc_fasync, +}; + +static struct miscdevice rtc_dev = { + .minor = RTC_MINOR, + .name = "rtc", + .fops = &rtc_fops, +}; + +static const struct file_operations rtc_proc_fops = { + .owner = THIS_MODULE, + .open = rtc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#if defined(RTC_IRQ) && !defined(__sparc__) +static irq_handler_t rtc_int_handler_ptr; +#endif + +static int __init rtc_init(void) +{ + struct proc_dir_entry *ent; +#if defined(__alpha__) || defined(__mips__) + unsigned int year, ctrl; + char *guess = NULL; +#endif +#ifdef __sparc__ + struct linux_ebus *ebus; + struct linux_ebus_device *edev; +#ifdef __sparc_v9__ + struct sparc_isa_bridge *isa_br; + struct sparc_isa_device *isa_dev; +#endif +#endif +#ifndef __sparc__ + void *r; +#endif + +#ifdef __sparc__ + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if(strcmp(edev->prom_node->name, "rtc") == 0) { + rtc_port = edev->resource[0].start; + rtc_irq = edev->irqs[0]; + goto found; + } + } + } +#ifdef __sparc_v9__ + for_each_isa(isa_br) { + for_each_isadev(isa_dev, isa_br) { + if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { + rtc_port = isa_dev->resource.start; + rtc_irq = isa_dev->irq; + goto found; + } + } + } +#endif + printk(KERN_ERR "rtc_init: no PC rtc found\n"); + return -EIO; + +found: + if (rtc_irq == PCI_IRQ_NONE) { + rtc_has_irq = 0; + goto no_irq; + } + + /* + * XXX Interrupt pin #7 in Espresso is shared between RTC and + * PCI Slot 2 INTA# (and some INTx# in Slot 1). + */ + if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) { + printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); + return -EIO; + } +no_irq: +#else + if (RTC_IOMAPPED) + r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); + else + r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); + if (!r) { + printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", + (long)(RTC_PORT(0))); + return -EIO; + } + +#ifdef RTC_IRQ + if (is_hpet_enabled()) { + rtc_int_handler_ptr = hpet_rtc_interrupt; + } else { + rtc_int_handler_ptr = rtc_interrupt; + } + + if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) { + /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ + printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); + if (RTC_IOMAPPED) + release_region(RTC_PORT(0), RTC_IO_EXTENT); + else + release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); + return -EIO; + } + hpet_rtc_timer_init(); + +#endif + +#endif /* __sparc__ vs. others */ + + if (misc_register(&rtc_dev)) { +#ifdef RTC_IRQ + free_irq(RTC_IRQ, NULL); +#endif + release_region(RTC_PORT(0), RTC_IO_EXTENT); + return -ENODEV; + } + + ent = create_proc_entry("driver/rtc", 0, NULL); + if (!ent) { +#ifdef RTC_IRQ + free_irq(RTC_IRQ, NULL); +#endif + release_region(RTC_PORT(0), RTC_IO_EXTENT); + misc_deregister(&rtc_dev); + return -ENOMEM; + } + ent->proc_fops = &rtc_proc_fops; + +#if defined(__alpha__) || defined(__mips__) + rtc_freq = HZ; + + /* Each operating system on an Alpha uses its own epoch. + Let's try to guess which one we are using now. */ + + if (rtc_is_updating() != 0) + msleep(20); + + spin_lock_irq(&rtc_lock); + year = CMOS_READ(RTC_YEAR); + ctrl = CMOS_READ(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(year); /* This should never happen... */ + + if (year < 20) { + epoch = 2000; + guess = "SRM (post-2000)"; + } else if (year >= 20 && year < 48) { + epoch = 1980; + guess = "ARC console"; + } else if (year >= 48 && year < 72) { + epoch = 1952; + guess = "Digital UNIX"; +#if defined(__mips__) + } else if (year >= 72 && year < 74) { + epoch = 2000; + guess = "Digital DECstation"; +#else + } else if (year >= 70) { + epoch = 1900; + guess = "Standard PC (1900)"; +#endif + } + if (guess) + printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); +#endif +#ifdef RTC_IRQ + if (rtc_has_irq == 0) + goto no_irq2; + + init_timer(&rtc_irq_timer); + rtc_irq_timer.function = rtc_dropped_irq; + spin_lock_irq(&rtc_lock); + rtc_freq = 1024; + if (!hpet_set_periodic_freq(rtc_freq)) { + /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ + CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); + } + spin_unlock_irq(&rtc_lock); +no_irq2: +#endif + + (void) init_sysctl(); + + printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); + + return 0; +} + +static void __exit rtc_exit (void) +{ + cleanup_sysctl(); + remove_proc_entry ("driver/rtc", NULL); + misc_deregister(&rtc_dev); + +#ifdef __sparc__ + if (rtc_has_irq) + free_irq (rtc_irq, &rtc_port); +#else + if (RTC_IOMAPPED) + release_region(RTC_PORT(0), RTC_IO_EXTENT); + else + release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); +#ifdef RTC_IRQ + if (rtc_has_irq) + free_irq (RTC_IRQ, NULL); +#endif +#endif /* __sparc__ */ +} + +module_init(rtc_init); +module_exit(rtc_exit); + +#ifdef RTC_IRQ +/* + * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. + * (usually during an IDE disk interrupt, with IRQ unmasking off) + * Since the interrupt handler doesn't get called, the IRQ status + * byte doesn't get read, and the RTC stops generating interrupts. + * A timer is set, and will call this function if/when that happens. + * To get it out of this stalled state, we just read the status. + * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. + * (You *really* shouldn't be trying to use a non-realtime system + * for something that requires a steady > 1KHz signal anyways.) + */ + +static void rtc_dropped_irq(unsigned long data) +{ + unsigned long freq; + + spin_lock_irq (&rtc_lock); + + if (hpet_rtc_dropped_irq()) { + spin_unlock_irq(&rtc_lock); + return; + } + + /* Just in case someone disabled the timer from behind our back... */ + if (rtc_status & RTC_TIMER_ON) + mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); + + rtc_irq_data += ((rtc_freq/HZ)<<8); + rtc_irq_data &= ~0xff; + rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ + + freq = rtc_freq; + + spin_unlock_irq(&rtc_lock); + + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); + + /* Now we have new data */ + wake_up_interruptible(&rtc_wait); + + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); +} +#endif + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_show(struct seq_file *seq, void *v) +{ +#define YN(bit) ((ctrl & bit) ? "yes" : "no") +#define NY(bit) ((ctrl & bit) ? "no" : "yes") + struct rtc_time tm; + unsigned char batt, ctrl; + unsigned long freq; + + spin_lock_irq(&rtc_lock); + batt = CMOS_READ(RTC_VALID) & RTC_VRT; + ctrl = CMOS_READ(RTC_CONTROL); + freq = rtc_freq; + spin_unlock_irq(&rtc_lock); + + + rtc_get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + seq_printf(seq, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + get_rtc_alm_time(&tm); + + /* + * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will + * match any value for that particular field. Values that are + * greater than a valid time, but less than 0xc0 shouldn't appear. + */ + seq_puts(seq, "alarm\t\t: "); + if (tm.tm_hour <= 24) + seq_printf(seq, "%02d:", tm.tm_hour); + else + seq_puts(seq, "**:"); + + if (tm.tm_min <= 59) + seq_printf(seq, "%02d:", tm.tm_min); + else + seq_puts(seq, "**:"); + + if (tm.tm_sec <= 59) + seq_printf(seq, "%02d\n", tm.tm_sec); + else + seq_puts(seq, "**\n"); + + seq_printf(seq, + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + YN(RTC_DST_EN), + NY(RTC_DM_BINARY), + YN(RTC_24H), + YN(RTC_SQWE), + YN(RTC_AIE), + YN(RTC_UIE), + YN(RTC_PIE), + freq, + batt ? "okay" : "dead"); + + return 0; +#undef YN +#undef NY +} + +static int rtc_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtc_proc_show, NULL); +} + +void rtc_get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long uip_watchdog = jiffies, flags; + unsigned char ctrl; +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_year; +#endif + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + + while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) + cpu_relax(); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Note that while the + * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is + * only updated by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&rtc_lock, flags); + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + /* Only set from 2.6.16 onwards */ + rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); + +#ifdef CONFIG_MACH_DECSTATION + real_year = CMOS_READ(RTC_DEC_YEAR); +#endif + ctrl = CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + BCD_TO_BIN(rtc_tm->tm_wday); + } + +#ifdef CONFIG_MACH_DECSTATION + rtc_tm->tm_year += real_year - 72; +#endif + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static void get_rtc_alm_time(struct rtc_time *alm_tm) +{ + unsigned char ctrl; + + /* + * Only the values that we read from the RTC are set. That + * means only tm_hour, tm_min, and tm_sec. + */ + spin_lock_irq(&rtc_lock); + alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); + alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); + alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); + ctrl = CMOS_READ(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(alm_tm->tm_sec); + BCD_TO_BIN(alm_tm->tm_min); + BCD_TO_BIN(alm_tm->tm_hour); + } +} + +#ifdef RTC_IRQ +/* + * Used to disable/enable interrupts for any one of UIE, AIE, PIE. + * Rumour has it that if you frob the interrupt enable/disable + * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to + * ensure you actually start getting interrupts. Probably for + * compatibility with older/broken chipset RTC implementations. + * We also clear out any old irq data after an ioctl() that + * meddles with the interrupt enable/disable bits. + */ + +static void mask_rtc_irq_bit_locked(unsigned char bit) +{ + unsigned char val; + + if (hpet_mask_rtc_irq_bit(bit)) + return; + val = CMOS_READ(RTC_CONTROL); + val &= ~bit; + CMOS_WRITE(val, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + + rtc_irq_data = 0; +} + +static void set_rtc_irq_bit_locked(unsigned char bit) +{ + unsigned char val; + + if (hpet_set_rtc_irq_bit(bit)) + return; + val = CMOS_READ(RTC_CONTROL); + val |= bit; + CMOS_WRITE(val, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + + rtc_irq_data = 0; +} +#endif + +MODULE_AUTHOR("Paul Gortmaker"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(RTC_MINOR); diff --git a/drivers/char/snapdog.c b/drivers/char/snapdog.c new file mode 100644 index 00000000..3b74dd1e --- /dev/null +++ b/drivers/char/snapdog.c @@ -0,0 +1,459 @@ +/****************************************************************************/ +/* + * SnapGear Hardware Watchdog driver (this WD cannot be stopped) + * + * Copyright 2004 David McCullough , All Rights Reserved. + * + * 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. + * + * based on softdog.c by Alan Cox + */ +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ +/* + * here we put the platform specific bits (headers/poke function) + */ + +#ifdef CONFIG_SH_SECUREEDGE5410 + #include + + static inline void enable_dog(void) {} + + static inline void poke_the_dog(void) + { + volatile char dummy; + dummy = * (volatile char *) 0xb8000000; + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#ifdef CONFIG_MACH_IPD + #include + + static volatile char *dog_addr = NULL; + + static inline void enable_dog(void) + { + dog_addr = (char *) ioremap(0x20000000, 32); + } + + static inline void poke_the_dog(void) + { + if (dog_addr) { + volatile char dummy = *dog_addr; + } + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#if defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_IVPN) || \ + defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \ + defined(CONFIG_MACH_SG640) || defined(CONFIG_MACH_SG720) || \ + defined(CONFIG_MACH_SG590) + #include + + static inline void enable_dog(void) + { + *IXP4XX_GPIO_GPCLKR &= 0xffff0000; + } + + static inline void poke_the_dog(void) + { + *IXP4XX_GPIO_GPOUTR ^= 0x4000; + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#if defined(CONFIG_MACH_SG8100) + #include + + static inline void enable_dog(void) + { + } + + static inline void poke_the_dog(void) + { + *IXP4XX_GPIO_GPOUTR ^= 0x2000; + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#if defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SHIVA1100) + #include + + static volatile unsigned char *wdtcs2; + + static inline void enable_dog(void) + { + /* CS7 is watchdog alive. Set it to 8bit and writable */ + *SG565_WATCHDOG_EXP_CS = 0xbfff0003; + wdtcs2 = (volatile unsigned char *) ioremap(SG565_WATCHDOG_BASE_PHYS, 512); + } + + static inline void poke_the_dog(void) + { + if (wdtcs2) + *wdtcs2 = 0; + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#ifdef CONFIG_GEODEWATCHDOG + #include + + static inline void enable_dog(void) {} + + static inline void poke_the_dog(void) + { + unsigned int v; + v = inl(0x6410); + outl((v | 0x200), 0x6410); + outl((v & ~0x200), 0x6410); + } + + static inline void the_dog_is_dead(void) {} + + #define HAS_HW_SERVICE 1 +#endif + +#ifndef HAS_HW_SERVICE + static inline void enable_dog(void) {} + static inline void poke_the_dog(void) {} + static inline void the_dog_is_dead(void) + { + machine_restart(NULL); + printk(KERN_CRIT "snapdog: reboot failed!.\n"); + } +#endif + +/****************************************************************************/ + +static unsigned long snapdog_last = 0; +static unsigned long snapdog_next = 0; +static int snapdog_service_required = 0; +static unsigned long snapdog_busy = 0; +static int snapdog_kernel = 0; +static int snapdog_timeout = 60; +static int snapdog_ltimeout = 300; +static int snapdog_use_long_timeout = 0; +static int snapdog_quiet = 0; +static int snapdog_warned = 0; +static int snapdog_stackdump = 64; + +module_param(snapdog_kernel, int, 0); +MODULE_PARM_DESC(snapdog_kernel, + "Watchdog is kernel only (userland servicing not required)"); + +module_param(snapdog_timeout, int, 0); +MODULE_PARM_DESC(snapdog_timeout, + "Watchdog timeout for user service in seconds"); + +module_param(snapdog_ltimeout, int, 0); +MODULE_PARM_DESC(snapdog_ltimeout, + "Watchdog 'long' timeout for user service in seconds"); + +module_param(snapdog_stackdump, int, 0); +MODULE_PARM_DESC(snapdog_stackdump, + "Number of long words to dump from the stack"); + +/****************************************************************************/ +/* + * a really dumb stack dump, we may need better on some platforms + * at least this one is implemented, unlike dump_stack which is largely + * just a stub :-( + */ + +static void snapdog_show_stack(struct pt_regs *regs) +{ + unsigned long i; + unsigned long *addr = &i; + + printk("Kernel stack:"); + for (i = 0; i < snapdog_stackdump; i++) { + if (i % 4 == 0) + printk("\n%08lx:", (unsigned long) addr); + printk(" 0x%08lx", *addr++); + } + printk("\n"); +} + +/****************************************************************************/ +/* + * Because we need to service this guy from deep in other more critical + * code, we export a function to do this that we can call where + * appropriate. + * + * Also the watchdog never stops, it is always running. We must service + * it until we are opened, then we stop servicing it if we are not looked + * after appropriately. + * + * I know there are much more clever ways to code the following, but then + * who would understand it, let alone know it did the right thing when + * jiffies wraps ;-) + */ + +void +snapdog_service(void) +{ + struct pt_regs *regs; + int the_dog_is_alive = 0; + + if (snapdog_kernel) { + the_dog_is_alive = 1; + } else if (!snapdog_service_required) { + the_dog_is_alive = 1; + } else if (snapdog_next < snapdog_last) { + if (jiffies < snapdog_next || jiffies > snapdog_last) + the_dog_is_alive = 1; + } else if (jiffies >= snapdog_last && jiffies < snapdog_next) { + the_dog_is_alive = 1; + } + + if (the_dog_is_alive) + poke_the_dog(); + else if (!snapdog_warned) { + snapdog_warned = 1; + printk(KERN_CRIT "snapdog: expired, allowing system reboot.\n"); + regs = get_irq_regs(); + if (regs) { + show_regs(regs); + snapdog_show_stack(regs); + } + the_dog_is_dead(); + } +} + +EXPORT_SYMBOL(snapdog_service); + +/****************************************************************************/ +/* + * bump the userland expiry + */ + +static inline void +snapdog_user_service(void) +{ + snapdog_last = jiffies; + if (snapdog_use_long_timeout) + snapdog_next = snapdog_last + HZ * snapdog_ltimeout; + else + snapdog_next = snapdog_last + HZ * snapdog_timeout; + snapdog_warned = 0; +} + +/****************************************************************************/ +/* + * Allow only one person to hold it open + */ + +static int +snapdog_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &snapdog_busy)) + return -EBUSY; + + /* Activate timer */ + snapdog_service_required = 1; + if (snapdog_use_long_timeout) { + /* Opening reverts to using short timeouts */ + snapdog_use_long_timeout = 0; + + if (!snapdog_quiet) { + printk(KERN_INFO "snapdog: now using short timeouts.\n"); + } + } + snapdog_user_service(); + + if (!snapdog_quiet) { + printk(KERN_INFO "snapdog: user servicing enabled (short=%d,long=%d).\n", + snapdog_timeout, snapdog_ltimeout); + } + + + /* Opening turns off quiet mode */ + snapdog_quiet = 0; + + + return 0; +} + +/****************************************************************************/ + +static int +snapdog_release(struct inode *inode, struct file *file) +{ + lock_kernel(); + if (!snapdog_quiet) { + if (!snapdog_service_required) { + printk(KERN_INFO + "snapdog: disabled user servicing of watchdog timer.\n"); + } else if (snapdog_use_long_timeout) { + printk(KERN_CRIT + "snapdog: device closed, watchdog will reboot!\n"); + } + } + clear_bit(0, &snapdog_busy); + unlock_kernel(); + + return 0; +} + +/****************************************************************************/ + +static ssize_t +snapdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (*ppos != file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + size_t i; + + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') { + snapdog_service_required = 0; + } + else if (c == 'T') { + if (!snapdog_quiet) { + printk(KERN_INFO "snapdog: now using long timeouts.\n"); + } + snapdog_use_long_timeout = 1; + } + else if (c == 'Q') { + /* Go quiet */ + snapdog_quiet = 1; + } + } + snapdog_user_service(); + return 1; + } + return 0; +} + +/****************************************************************************/ + +static int +snapdog_ioctl( + struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + .options = WDIOF_MAGICCLOSE, + .identity = "HW/SW Watchdog for SnapGear", + }; + + switch (cmd) { + default: + return(-ENOIOCTLCMD); + + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info __user *) arg, &ident, sizeof(ident))) + return -EFAULT; + return(0); + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return(put_user(0, (int __user *) arg)); + + case WDIOC_KEEPALIVE: + snapdog_user_service(); + return(0); + } +} + +/****************************************************************************/ + +static struct file_operations snapdog_fops = { + .owner = THIS_MODULE, + .write = snapdog_write, + .ioctl = snapdog_ioctl, + .open = snapdog_open, + .release = snapdog_release, +}; + + +static struct miscdevice snapdog_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &snapdog_fops, +}; + +/****************************************************************************/ + +static const char banner[] __initdata = + KERN_INFO "snapdog: HW/SW watchdog timer for SnapGear/Others\n"; + +static int __init +watchdog_init(void) +{ + int ret; + + enable_dog(); + + ret = misc_register(&snapdog_miscdev); + if (ret) + return ret; + + printk(banner); + + return 0; +} + +/****************************************************************************/ + +static void __exit +watchdog_exit(void) +{ + misc_deregister(&snapdog_miscdev); +} + +/****************************************************************************/ + +module_init(watchdog_init); +module_exit(watchdog_exit); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("Driver for SnapGear HW/SW watchdog timer(s)"); +MODULE_LICENSE("GPL"); + +/****************************************************************************/ diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 0187b118..a1af5a4b 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -81,6 +81,19 @@ config 21285_WATCHDOG "If in doubt, leave it out" - say N. +config UC7110WDT + tristate "Moxa ART CPU watchdog" + depends on ARCH_MOXART + help + Author : Jimmy_chen@moxa.com.tw + Watchdog timer embedded into moxart chips. This will + reboot your system when timeout is reached. + + NOTE: once enabled, this timer cannot be disabled. + + To compile this driver as a module, choose M here: the + module will be called em1240wdt.ko. + config 977_WATCHDOG tristate "NetWinder WB83C977 watchdog" depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER @@ -553,6 +566,21 @@ config INDYDOG timer expired and no process has written to /dev/watchdog during that time. +# Nios2 Architecture +config AVALON_WDT + tristate "Nios2 Watchdog (Avalon)" + depends on WATCHDOG && NIOS2 + help + This is a driver for a timer connected to the avalon switch fabric wich is + configured as a watchdog. + Once started the watchdog cannot be stopped! + This driver assumes you named the watchdog timer watchdog. + If you didn't you should rename the component or change the definition in + drivers/char/watchdog/avalonwdt.c + + Most people will say N. + + # S390 Architecture config ZVM_WATCHDOG @@ -618,6 +646,15 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +# M68KNOMMU Architecture + +config WDT_M5272 + tristate "MCF5272 Hardware Watchdog support" + depends on WATCHDOG && M5272 + help + Say Y here to suuport the hardware watchdog capability on Freescale + Coldfire MCF5272 machines. + # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 36440497..0020881a 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o +obj-$(CONFIG_UC7110WDT) += uc7110wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o @@ -80,5 +81,10 @@ obj-$(CONFIG_SH_WDT) += shwdt.o # SPARC64 Architecture +# NIOS2 Architecture +obj-$(CONFIG_AVALON_WDT) +=avalonwdt.o + # Architecture Independant obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o + +obj-$(CONFIG_WDT_M5272) += m5272_wdt.o diff --git a/drivers/char/watchdog/avalonwdt.c b/drivers/char/watchdog/avalonwdt.c new file mode 100644 index 00000000..ff374471 --- /dev/null +++ b/drivers/char/watchdog/avalonwdt.c @@ -0,0 +1,220 @@ +/* + * WDT driver for the Nios2 + * + * (c) Copyright 2005 Walter Goossens + * Neither Walter Goossens nor Emdes Embedded Systems admit liability + * nor provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.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. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Change this line if you used another name in your PTF file. + +#define AVALON_WDT_BASE na_watchdog +#define AVALON_WDT_STATUS AVALON_WDT_BASE +#define AVALON_WDT_CONTROL (AVALON_WDT_BASE + 0x04) +#define AVALON_WDT_PERIODL (AVALON_WDT_BASE + 0x08) +#define AVALON_WDT_PERIODH (AVALON_WDT_BASE + 0x0C) +#define AVALON_WDT_SIZE 0x18 + +#define AVALON_WDT_RUN_BIT 0x04 + +static unsigned long wdt_is_open; + +/** + * avalon_wdt_start: + * + * Start the watchdog driver. + */ +static int avalon_wdt_start(void) { + outw_p(inw_p(AVALON_WDT_CONTROL) | AVALON_WDT_RUN_BIT, AVALON_WDT_CONTROL); + printk(KERN_INFO "avalonwdt: Starting watchdog timer\n"); + return 0; +} + +/** + * avalon_wdt_ping: + * + * Reload counter one with the watchdog heartbeat. + */ +static int avalon_wdt_ping(void) { + //It doesn't matter what value we write + outw_p(1,AVALON_WDT_PERIODL); + return 0; +} + +/** + * avalon_wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t avalon_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + if(count) { + avalon_wdt_ping(); + } + return count; +} + +/** + * avalon_wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + +static int avalon_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; + + static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = "Nios2_avalon_wdt", + }; + + switch(cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + avalon_wdt_ping(); + return 0; + default: + return -ENOIOCTLCMD; + } +} + +/** + * avalon_wdt_open: + * @inode: inode of device + * @file: file handle to device + * + * The watchdog device has been opened. The watchdog device is single + * open and on opening we load the counters. + * The timeout depends on the value you selected in SOPC-builder. + */ +static int avalon_wdt_open(struct inode *inode, struct file *file) { + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + avalon_wdt_start(); + return nonseekable_open(inode, file); +} + +/** + * avalon_wdt_release: + * @inode: inode to board + * @file: file handle to board + * + */ +static int avalon_wdt_release(struct inode *inode, struct file *file) { + clear_bit(0, &wdt_is_open); + printk(KERN_CRIT "avalonwdt: WDT device closed unexpectedly. WDT will (can) not stop!\n"); + avalon_wdt_ping(); + return 0; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations avalon_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = avalon_wdt_write, + .ioctl = avalon_wdt_ioctl, + .open = avalon_wdt_open, + .release = avalon_wdt_release, +}; + +static struct miscdevice avalon_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &avalon_wdt_fops, +}; + +/** + * cleanup_module: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 30 seconds or reboot. + */ + +static void __exit avalon_wdt_exit(void) +{ + misc_deregister(&avalon_wdt_miscdev); + release_region(AVALON_WDT_BASE,AVALON_WDT_SIZE); +} + +/** + * avalon_wdt_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + +static int __init avalon_wdt_init(void) +{ + int ret; + + if (!request_region(AVALON_WDT_BASE, AVALON_WDT_SIZE, "Nios2_avalon_wdt")) { + printk(KERN_ERR "wdt: I/O address 0x%08x already in use\n", AVALON_WDT_BASE); + return -EBUSY; + } + ret = misc_register(&avalon_wdt_miscdev); + if (ret) { + printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); + release_region(AVALON_WDT_BASE,AVALON_WDT_SIZE); + return ret; + } + + printk(KERN_INFO "Nios2 Avalon Watchdog driver 0.01 at 0x%08x\n", AVALON_WDT_BASE); + return 0; +} + +module_init(avalon_wdt_init); +module_exit(avalon_wdt_exit); + +MODULE_AUTHOR("Walter Goossens"); +MODULE_DESCRIPTION("Driver for Nios2 Watchdog"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 5864bb86..dd40c93f 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -5,11 +5,11 @@ * * Author: Deepak Saxena * - * Copyright 2004 (c) MontaVista, Software, Inc. + * Copyright 2004 (c) MontaVista, Software, Inc. * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any + * + * 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. */ @@ -28,7 +28,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; static int heartbeat = 60; /* (secs) Default is 1 minute */ -static unsigned long wdt_status; +static unsigned long wdt_status; static unsigned long boot_status; #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) @@ -46,7 +46,7 @@ wdt_enable(void) *IXP4XX_OSWK = 0; } -static void +static void wdt_disable(void) { *IXP4XX_OSWK = IXP4XX_WDT_KEY; @@ -67,7 +67,7 @@ ixp4xx_wdt_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static ssize_t +static ssize_t ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) { if (len) { @@ -98,8 +98,8 @@ static struct watchdog_info ident = { }; -static int -ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +static int +ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOTTY; @@ -196,7 +196,7 @@ static int __init ixp4xx_wdt_init(void) if (ret == 0) printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat); - boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? + boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? WDIOF_CARDRESET : 0; return ret; diff --git a/drivers/char/watchdog/m5272_wdt.c b/drivers/char/watchdog/m5272_wdt.c new file mode 100644 index 00000000..3df89246 --- /dev/null +++ b/drivers/char/watchdog/m5272_wdt.c @@ -0,0 +1,228 @@ +/* + * Watchdog driver for the MCF5272 + * + * (c) Copyright 2005 Javier Herrero + * Based on SoftDog driver by Alan Cox + * + * 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. + * + * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2005 Javier Herrero + * + * 03/05/2005 Initial release + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define M5272_CLOSE_MAGIC (0x5afc4453) + +static unsigned long m5272wdt_users; +static int expect_close; +static unsigned short wdt_reset_ref; +static int boot_status; +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +/* + * Allow only one person to hold it open + */ +static int m5272dog_open(struct inode *inode, struct file *file) +{ + unsigned short* w; + + nonseekable_open(inode, file); + if (test_and_set_bit(1,&m5272wdt_users)) + return -EBUSY; + + /* Activate M5272 Watchdog timer */ + + w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR); + *w = wdt_reset_ref | 0x0001; + w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR); + *w = 0; + return 0; +} + +/* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + * Oddly, the watchdog can only be enabled, but we can turn off + * the interrupt, which appears to prevent the watchdog timing out. + */ +static int m5272dog_release(struct inode *inode, struct file *file) +{ + unsigned short* w; + + w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR); + + if (expect_close == M5272_CLOSE_MAGIC) { + *w = 0; + } else { + printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n"); + } + clear_bit(1, &m5272wdt_users); + expect_close = 0; + return 0; +} + +static ssize_t m5272dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + unsigned short* w; + + if (len) { + if (!nowayout) { + size_t i; + + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = M5272_CLOSE_MAGIC; + } + } + /* Refresh watchdog timer. */ + w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR); + *w = 0; + } + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | + WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "MCF5272 Watchdog", +}; + +static int m5272dog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = -ENOIOCTLCMD; + int time; + unsigned short* w; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(boot_status, (int *)arg); + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(time, (int *)arg); + if (ret) + break; + + if (time <= 0 || time > (32768*16384/MCF_CLK)) { + ret = -EINVAL; + break; + } + + wdt_reset_ref = (MCF_CLK / 16384) * time; + w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR); + *w = wdt_reset_ref | 0x0001; + /*fall through*/ + + case WDIOC_GETTIMEOUT: + ret = put_user(wdt_reset_ref * 16384 / MCF_CLK, (int *)arg); + break; + + case WDIOC_KEEPALIVE: + w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR); + *w = 0; + ret = 0; + break; + } + return ret; +} + +static struct file_operations m5272dog_fops = +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = m5272dog_write, + .ioctl = m5272dog_ioctl, + .open = m5272dog_open, + .release = m5272dog_release, +}; + +static struct miscdevice m5272dog_miscdev = +{ + .minor = WATCHDOG_MINOR, + .name = "MCF5272 watchdog", + .fops = &m5272dog_fops, +}; + +static int margin __initdata = 16; /* (secs) Default is 1 minute */ + +static int __init m5272dog_init(void) +{ + int ret; + + /* + * Read the reset status, and save it for later. If + * we suspend, RCSR will be cleared, and the watchdog + * reset reason will be lost. + */ +// boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0; + wdt_reset_ref = (MCF_CLK / 16384) * margin; + + ret = misc_register(&m5272dog_miscdev); + if (ret == 0) + printk("MCF5272 Watchdog Timer: timer margin %d sec\n", + margin); + + return ret; +} + +static void __exit m5272dog_exit(void) +{ + misc_deregister(&m5272dog_miscdev); +} + +module_init(m5272dog_init); +module_exit(m5272dog_exit); + +MODULE_AUTHOR("Javier Herrero "); +MODULE_DESCRIPTION("MCF5272 Watchdog"); + +module_param(margin, int, 0); +MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 16s)"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/uc7110wdt.c b/drivers/char/watchdog/uc7110wdt.c new file mode 100644 index 00000000..d0f5d77c --- /dev/null +++ b/drivers/char/watchdog/uc7110wdt.c @@ -0,0 +1,505 @@ +/* + * History: + * Date Aurhor Comment + * 02-23-2006 Victor Yu. Create it. + * 08-15-2006 Victor Yu. Modify to support UC-7110. + * 02-09-2007 Victor Yu. Porting to kernel version 2.6.19. + */ +//#define __KERNEL_SYSCALLS__ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +//#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define VICTOR_DEBUG +#ifdef VICTOR_DEBUG +#define dbg_printk(x...) printk(x) +#else +#define dbg_printk(x...) +#endif + +#define MOXA_WATCHDOG_VERSION "1.0" +#define MOXA_WATCHDOG_MINOR WATCHDOG_MINOR +#define DEFAULT_WATCHDOG_TIME (30UL*1000UL) // 30 seconds +#define WATCHDOG_MIN_TIME 50UL // 50 msec +#define WATCHDOG_MAX_TIME (60UL*1000UL) // 60 seconds +#define WATCHDOG_TOL_TIME (500UL) // 500 msec, for watchdog timer polling +#define WATCHDOG_TOL_COUNT_TIME (1000UL) // 1 seconds, for watchdog timer count +#define WATCHDOG_COUNTER(x) ((APB_CLK/1000UL)*(x)) +#define WATCHDOG_JIFFIES(x) ((((x)+WATCHDOG_TOL_TIME)*HZ)/1000UL) + +#if 0 // mask by Victor Yu. 05-15-2006 +static spinlock_t swtdlock=SPIN_LOCK_UNLOCKED; +#endif +static int opencounts=0; +static int swtduserenabled=0; +static unsigned long swtdtime=DEFAULT_WATCHDOG_TIME; +static struct timer_list swtdtimer; +static struct work_struct rebootqueue; + +static void swtd_enable(void) +{ + *(volatile unsigned int *)(CPE_WATCHDOG_BASE+4) = WATCHDOG_COUNTER(swtdtime+WATCHDOG_TOL_COUNT_TIME); + *(volatile unsigned int *)(CPE_WATCHDOG_BASE+8) = 0x5ab9; + *(volatile unsigned int *)(CPE_WATCHDOG_BASE+12) = 0x03; +} + +static void swtd_disable(void) +{ + *(volatile unsigned int *)(CPE_WATCHDOG_BASE+12) = 0; +} + +#define IOCTL_WATCHDOG_ENABLE 1 // enable watch dog and set time (unint msec) +#define IOCTL_WATCHDOG_DISABLE 2 // disable watch dog, kernle do it +#define IOCTL_WATCHDOG_GET_SETTING 3 // get now setting about mode and time +#define IOCTL_WATCHDOG_ACK 4 // to ack watch dog +struct swtd_set_struct { + int mode; + unsigned long time; +}; +static int swtd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + unsigned long time; + struct swtd_set_struct nowset; + unsigned long flags; + + switch ( cmd ) { + case IOCTL_WATCHDOG_ENABLE : + if ( copy_from_user(&time, (void *)arg, sizeof(time)) ) + return -EFAULT; + if ( time < WATCHDOG_MIN_TIME || time > WATCHDOG_MAX_TIME ) + return -EINVAL; +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); + del_timer(&swtdtimer); + swtd_disable(); + swtdtime = time; + swtduserenabled = 1; + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + } + swtdtime = time; + swtduserenabled = 1; + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + break; + case IOCTL_WATCHDOG_DISABLE : +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtduserenabled = 0; + swtdtime = DEFAULT_WATCHDOG_TIME; + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + } + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtduserenabled = 0; + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + break; + case IOCTL_WATCHDOG_GET_SETTING : + nowset.mode = swtduserenabled; + nowset.time = swtdtime; + if ( copy_to_user((void *)arg, &nowset, sizeof(nowset)) ) + return -EFAULT; + break; + case IOCTL_WATCHDOG_ACK : +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + } + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + break; + default: + return -EINVAL; + } + return 0; +} + +static int swtd_open(struct inode *inode, struct file *file) +{ + unsigned long flags; + + if ( MINOR(inode->i_rdev) != MOXA_WATCHDOG_MINOR ) + return -ENODEV; +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); + opencounts++; + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#if 0 // mask by Victor Yu. 05-15-2006 + if ( swtduserenabled == 0 ) { + swtduserenabled = 1; + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + } +#endif + opencounts++; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + return 0; +} + +static int swtd_release(struct inode *inode, struct file *file) +{ + unsigned long flags; + +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + dbg_printk("swtd_release entry.\n"); + opencounts--; + if ( opencounts <= 0 ) { +#if 0 // mask by Victor Yu. 02-23-2006 + if ( signal_pending(current) ) { + dbg_printk("swtd_release has signal pending\n"); + dbg_printk("parent signal blocked=0x%x,0x%x, pending=0x%x,0x%x\n", current->parent->blocked.sig[0], current->parent->blocked.sig[1], current->parent->pending.signal.sig[0], current->parent->pending.signal.sig[1]); + dbg_printk("signal blocked=0x%x,0x%x, pending=0x%x,0x%x\n", current->blocked.sig[0], current->blocked.sig[1], current->pending.signal.sig[0], current->pending.signal.sig[1]); + if ( sigismember(¤t->parent->blocked, SIGKILL) ) { + dbg_printk("swtd_release get SIGKILL signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->blocked, SIGKILL) ) { + dbg_printk("swtd_release get SIGKILL signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->parent->blocked, SIGCHLD) ) { + dbg_printk("swtd_release get SIGCHLD signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->blocked, SIGCHLD) ) { + dbg_printk("swtd_release get SIGCHLD signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->parent->blocked, SIGTERM) ) { + dbg_printk("swtd_release get SIGTERM signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->blocked, SIGTERM) ) { + dbg_printk("swtd_release get SIGTERM signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->parent->blocked, SIGINT) ) { + dbg_printk("swtd_release get SIGINT signal\n"); + goto swtd_release_l1; + } + if ( sigismember(¤t->blocked, SIGINT) ) { + dbg_printk("swtd_release get SIGINT signal\n"); + goto swtd_release_l1; + } +#ifdef VICTOR_DEBUG // add by Victor Yu. 02-23-2006 + if ( sigismember(¤t->parent->blocked, SIGSTOP) ) { + dbg_printk("swtd_release get SIGSTOP signal\n"); + } + if ( sigismember(¤t->parent->blocked, SIGHUP) ) { + dbg_printk("swtd_release get SIGHUP signal\n"); + } + if ( sigismember(¤t->parent->blocked, SIGQUIT) ) { + dbg_printk("swtd_release get SIGQUIT signal\n"); + } + if ( sigismember(¤t->parent->blocked, SIGTSTP) ) { + dbg_printk("swtd_release get SIGTSTP signal\n"); + } + if ( sigismember(¤t->parent->blocked, SIGABRT) ) { + dbg_printk("swtd_release get SIGABRT signal\n"); + } + if ( sigismember(¤t->parent->blocked, SIGSEGV) ) { + dbg_printk("swtd_release get SIGSEGV signal\n"); + } +#endif + } else { // normal close the file handle +swtd_release_l1: +#endif + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtduserenabled = 0; +#if 0 // mask by Victor Yu. 05-15-2006 + swtdtime = DEFAULT_WATCHDOG_TIME; + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); +#endif + } +#if 0 // mask by Victor Yu. 02-23-2006 + } +#endif + opencounts = 0; + } +#if 0 // mask by Victor Yu. 05-15-1006 + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + return 0; +} + +static void swtd_reboot(void *unused) +{ + char *argv[2], *envp[5]; + + if ( in_interrupt() ) + return; + if ( !current->fs->root ) + return; + argv[0] = "/bin/reboot"; + argv[1] = 0; + envp[0] = "HOME=/"; + envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp[2] = 0; + call_usermodehelper(argv[0], argv, envp, 0); +} + +static void swtd_poll(unsigned long ignore) +{ + unsigned long flags; + +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + swtd_disable(); + del_timer(&swtdtimer); +#if 0 // mask by Victor Yu. 05-15-2006 + if ( swtduserenabled ) { + dbg_printk("Now reboot the system.\n"); + schedule_work(&rebootqueue); + } else { + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + } + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 + dbg_printk("Now reboot the system.\n"); + schedule_work(&rebootqueue); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif +} + +static int swtd_proc_output(char *buf) +{ + char *p; + + p = buf; + p += sprintf(p, + "user enable\t: %d\n" + "ack time\t: %d msec\n", + swtduserenabled, (int)swtdtime); + return p - buf; +} + +static int swtd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len=swtd_proc_output(page); + + if ( len <= off + count ) + *eof = 1; + *start = page + off; + len -= off; + if ( len > count ) + len = count; + if ( len < 0 ) + len = 0; + return len; +} + +static struct file_operations swtd_fops = { + owner:THIS_MODULE, + llseek:NULL, + ioctl:swtd_ioctl, + open:swtd_open, + release:swtd_release, +}; +static struct miscdevice swtd_dev = { + MOXA_WATCHDOG_MINOR, + "swtd", + &swtd_fops +}; + +static void __exit moxa_swtd_exit(void) +{ + unsigned long flags; + +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#endif + if ( swtduserenabled ) { + swtd_disable(); + del_timer(&swtdtimer); + swtduserenabled = 0; + opencounts = 0; + } +#if 0 // mask by Victor Yu. 05-15-2006 + spin_unlock(&swtdlock); +#else // add by Victor Yu. 05-15-2006 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +#endif + misc_deregister(&swtd_dev); +} + +static int __init moxa_swtd_init(void) +{ + // register misc + if ( misc_register(&swtd_dev) ) { + printk("Moxa ART CPU WatchDog: Register misc fail !\n"); + goto moxa_swtd_init_err; + } + INIT_WORK(&rebootqueue, swtd_reboot, NULL); +#if 0 // mask by Victor Yu. 05-15-2006 + spin_lock(&swtdlock); +#endif + init_timer(&swtdtimer); + swtdtimer.function = swtd_poll; +#if 0 // mask by Victor Yu. 05-15-2006 + swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime); + add_timer(&swtdtimer); + swtd_enable(); + spin_unlock(&swtdlock); +#endif + create_proc_read_entry("driver/swtd", 0, 0, swtd_read_proc, NULL); + printk("Moxa ART CPU WatchDog driver v" MOXA_WATCHDOG_VERSION "\n"); + + return 0; + +moxa_swtd_init_err: + misc_deregister(&swtd_dev); + return -ENOMEM; +} + +module_init(moxa_swtd_init); +module_exit(moxa_swtd_exit); + +MODULE_AUTHOR("Victor Yu"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 9d67320e..27c45926 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -132,7 +132,9 @@ int vid_from_reg(int val, u8 vrm) val &= 0x7f; return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000); default: /* report 0 for unknown */ +#ifndef CONFIG_ARM printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n"); +#endif return 0; } } diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 3ce82548..01c7be8c 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -778,6 +778,10 @@ static void lm87_init_client(struct i2c_client *client) struct lm87_data *data = i2c_get_clientdata(client); u8 config; +#ifdef CONFIG_MACH_SG720 + lm87_write_value(client, LM87_REG_CHANNEL_MODE, 0x03); +#endif + data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); data->vrm = vid_which_vrm(); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 510816c1..8ed9157b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -254,6 +254,16 @@ config I2C_POWERMAC This support is also available as a module. If so, the module will be called i2c-powermac. +config I2C_MCF + tristate "MCF ColdFire" + depends on I2C && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + I2C on most ColdFire CPUs + + This driver can also be built as a module. If so, the module + will be called i2c-mcf. + config I2C_MPC tristate "MPC107/824x/85xx/52xx/86xx" depends on I2C && PPC32 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 493c8728..c0445670 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_MCF) += i2c-mcf.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index d108ab49..d68f4c77 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -491,6 +491,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) memcpy(new_adapter->name, pdev->name, strlen(pdev->name)); new_adapter->id = I2C_HW_IOP3XX; new_adapter->owner = THIS_MODULE; + new_adapter->class = I2C_CLASS_HWMON, new_adapter->dev.parent = &pdev->dev; /* diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 68fe863f..4d503e26 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -1,7 +1,7 @@ /* * drivers/i2c/busses/i2c-ixp4xx.c * - * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have + * Intel's IXP42x XScale NPU chipsets (IXP420, 421, 422, 425) do not have * an on board I2C controller but provide 16 GPIO pins that are often * used to create an I2C bus. This driver provides an i2c_adapter * interface that plugs in under algo_bit and drives the GPIO pins @@ -16,12 +16,12 @@ * warranty of any kind, whether express or implied. * * NOTE: Since different platforms will use different GPIO pins for - * I2C, this driver uses an IXP4xx-specific platform_data + * I2C, this driver uses an IXP42x-specific platform_data * pointer to pass the GPIO numbers to the driver. This - * allows us to support all the different IXP4xx platforms + * allows us to support all the different IXP42x platforms * w/o having to put #ifdefs in this driver. * - * See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a + * See arch/arm/mach-ixp42x/ixdp425.c for an example of building a * device list and filling in the ixp4xx_i2c_pins data structure * that is passed as the platform_data to this driver. */ @@ -32,49 +32,50 @@ #include #include #include +#include -#include /* Pick up IXP4xx-specific bits */ +#include /* Pick up IXP42x-specific bits */ -static inline int ixp4xx_scl_pin(void *data) +static inline int ixp42x_scl_pin(void *data) { return ((struct ixp4xx_i2c_pins*)data)->scl_pin; } -static inline int ixp4xx_sda_pin(void *data) +static inline int ixp42x_sda_pin(void *data) { return ((struct ixp4xx_i2c_pins*)data)->sda_pin; } -static void ixp4xx_bit_setscl(void *data, int val) +static void ixp42x_bit_setscl(void *data, int val) { - gpio_line_set(ixp4xx_scl_pin(data), 0); - gpio_line_config(ixp4xx_scl_pin(data), + gpio_line_set(ixp42x_scl_pin(data), 0); + gpio_line_config(ixp42x_scl_pin(data), val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); } -static void ixp4xx_bit_setsda(void *data, int val) +static void ixp42x_bit_setsda(void *data, int val) { - gpio_line_set(ixp4xx_sda_pin(data), 0); - gpio_line_config(ixp4xx_sda_pin(data), + gpio_line_set(ixp42x_sda_pin(data), 0); + gpio_line_config(ixp42x_sda_pin(data), val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); } -static int ixp4xx_bit_getscl(void *data) +static int ixp42x_bit_getscl(void *data) { int scl; - gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_scl_pin(data), &scl); + gpio_line_config(ixp42x_scl_pin(data), IXP4XX_GPIO_IN ); + gpio_line_get(ixp42x_scl_pin(data), &scl); return scl; } -static int ixp4xx_bit_getsda(void *data) +static int ixp42x_bit_getsda(void *data) { int sda; - gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_sda_pin(data), &sda); + gpio_line_config(ixp42x_sda_pin(data), IXP4XX_GPIO_IN ); + gpio_line_get(ixp42x_sda_pin(data), &sda); return sda; } @@ -117,10 +118,10 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) * algo_data->data. */ drv_data->algo_data.data = gpio; - drv_data->algo_data.setsda = ixp4xx_bit_setsda; - drv_data->algo_data.setscl = ixp4xx_bit_setscl; - drv_data->algo_data.getsda = ixp4xx_bit_getsda; - drv_data->algo_data.getscl = ixp4xx_bit_getscl; + drv_data->algo_data.setsda = ixp42x_bit_setsda; + drv_data->algo_data.setscl = ixp42x_bit_setscl; + drv_data->algo_data.getsda = ixp42x_bit_getsda; + drv_data->algo_data.getscl = ixp42x_bit_getscl; drv_data->algo_data.udelay = 10; drv_data->algo_data.timeout = 100; @@ -159,20 +160,20 @@ static struct platform_driver ixp4xx_i2c_driver = { }, }; -static int __init ixp4xx_i2c_init(void) +static int __init ixp42x_i2c_init(void) { return platform_driver_register(&ixp4xx_i2c_driver); } -static void __exit ixp4xx_i2c_exit(void) +static void __exit ixp42x_i2c_exit(void) { platform_driver_unregister(&ixp4xx_i2c_driver); } -module_init(ixp4xx_i2c_init); -module_exit(ixp4xx_i2c_exit); +module_init(ixp42x_i2c_init); +module_exit(ixp42x_i2c_exit); -MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems"); +MODULE_DESCRIPTION("GPIO-based I2C driver for IXP42x systems"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Deepak Saxena "); diff --git a/drivers/i2c/busses/i2c-mcf.c b/drivers/i2c/busses/i2c-mcf.c new file mode 100644 index 00000000..79b19925 --- /dev/null +++ b/drivers/i2c/busses/i2c-mcf.c @@ -0,0 +1,556 @@ +/* + i2c-mcf5282.c - Part of lm_sensors, Linux kernel modules for hardware monitoring + + Copyright (c) 2005, Derek CL Cheung + + + Copyright (c) 2006, emlix and Freescale + Sebastian Hess + Yaroslav Vinogradov + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + + v0.2 29 May 2006 + Modified to be more generic and added support for + i2c_master_xfer + + This I2C adaptor supports the ColdFire 5282 CPU I2C module. Since most Coldfire + CPUs' I2C module use the same register set (e.g., MCF5249), the code is very + portable and re-usable to other Coldfire CPUs. + + The transmission frequency is set at about 100KHz for the 5282Lite CPU board with + 8MHz crystal. If the CPU board uses different system clock frequency, you should + change the following line: + static int __init i2c_coldfire_init(void) + { + ......... + // Set transmission frequency 0x15 = ~100kHz + *MCF_I2C_I2FDR = 0x15; + ........ + } + + Remember to perform a dummy read to set the ColdFire CPU's I2C module for read before + reading the actual byte from a device + + The I2C_SM_BUS_BLOCK_DATA function are not yet ready but most lm_senors do not care + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-mcf.h" + + +static struct i2c_algorithm coldfire_algorithm = { + /*.name = "ColdFire I2C algorithm", + .id = I2C_ALGO_SMBUS,*/ + .smbus_xfer = coldfire_i2c_access, + .master_xfer = coldfire_i2c_master, + .functionality = coldfire_func, +}; + + +static struct i2c_adapter coldfire_adapter = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .algo = &coldfire_algorithm, + .name = "ColdFire I2C adapter", +}; + + +__u16 lastaddr; +__u16 lastop; + +static inline int coldfire_do_first_start(__u16 addr,__u16 flags) +{ + int err; + /* + * Generate a stop and put the I2C module into slave mode + */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + /* + * Generate a new Start signal + */ + err = coldfire_i2c_start(flags & I2C_M_RD ? I2C_SMBUS_READ : I2C_SMBUS_WRITE, + addr, FIRST_START); + if(err) return err; + + lastaddr = addr; + lastop = flags & I2C_M_RD; /* Ensure everything for new start */ + return 0; +} + + +/* + * read one byte data from the I2C bus + */ +static int coldfire_read_data(u8 * const rxData, const enum I2C_ACK_TYPE ackType) { + + int timeout; + + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX; /* master receive mode */ + + if (ackType == NACK) + *MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; /* generate NA */ + else + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* generate ACK */ + + + /* read data from the I2C bus */ + *rxData = *MCF_I2C_I2DR; + + /* printk(">>> %s I2DR data is %.2x \n", __FUNCTION__, *rxData); */ + + /* wait for data transfer to complete */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, timeout); + + + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0 ) + return -1; + else + return 0; + +}; + + +/* + * write one byte data onto the I2C bus + */ +static int coldfire_write_data(const u8 txData) { + + int timeout; + + timeout = 500; + + *MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; /* I2C module into TX mode */ + *MCF_I2C_I2DR = txData; /* send the data */ + + /* wait for data transfer to complete */ + /* rely on the interrupt handling bit */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <=0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, timeout); + + + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0 ) + return -1; + else + return 0; + +}; + + + + +/* + * Generate I2C start or repeat start signal + * Combine the 7 bit target_address and the R/W bit and put it onto the I2C bus + */ +static int coldfire_i2c_start(const char read_write, const u16 target_address, const enum I2C_START_TYPE start_type) { + + int timeout; + + // printk(">>> %s START TYPE %s \n", __FUNCTION__, start_type == FIRST_START ? "FIRST_START" : "REPEAT_START"); + + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IEN; + + if (start_type == FIRST_START) { + /* Make sure the I2C bus is idle */ + timeout = 500; /* 500us timeout */ + while (timeout-- && (*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk("%s - I2C bus always busy in the past 500us timeout is %d \n", __FUNCTION__, timeout); + goto check_rc; + } + /* generate a START and put the I2C module into MASTER TX mode*/ + *MCF_I2C_I2CR |= (MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_MTX); + + /* wait for bus busy to be set */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk("%s - I2C bus is never busy after START. Timeout is %d \n", __FUNCTION__, timeout); + goto check_rc; + } + + } else { + /* this is repeat START */ + udelay(500); /* need some delay before repeat start */ + *MCF_I2C_I2CR |= (MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_RSTA); + } + + + /* combine the R/W bit and the 7 bit target address and put it onto the I2C bus */ + *MCF_I2C_I2DR = ((target_address & 0x7F) << 1) | (read_write == I2C_SMBUS_WRITE ? 0x00 : 0x01); + + /* wait for bus transfer to complete */ + /* when one byte transfer is completed, IIF set at the faling edge of the 9th clock */ + timeout = 500; + while (timeout-- && !(*MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk("%s - I2C IIF never set. Timeout is %d \n", __FUNCTION__, timeout); + + +check_rc: + /* reset the interrupt bit */ + *MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; + + if (timeout <= 0) + return -1; + else + return 0; +}; + + +/* + * 5282 SMBUS supporting functions + */ + +static s32 coldfire_i2c_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + int i, len, rc = 0; + u8 rxData, tempRxData[2]; + + switch (size) { + case I2C_SMBUS_QUICK: + rc = coldfire_i2c_start(read_write, addr, FIRST_START); /* generate START */ + break; + case I2C_SMBUS_BYTE: + rc = coldfire_i2c_start(read_write, addr, FIRST_START); + *MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; /* generate NA */ + if (read_write == I2C_SMBUS_WRITE) + rc += coldfire_write_data(command); + else { + coldfire_read_data(&rxData, NACK); /* dummy read */ + rc += coldfire_read_data(&rxData, NACK); + data->byte = rxData; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* reset ACK bit */ + break; + case I2C_SMBUS_BYTE_DATA: + rc = coldfire_i2c_start(I2C_SMBUS_WRITE, addr, FIRST_START); + rc += coldfire_write_data(command); + if (read_write == I2C_SMBUS_WRITE) + rc += coldfire_write_data(data->byte); + else { + /* This is SMBus READ Byte Data Request. Perform REPEAT START */ + rc += coldfire_i2c_start(I2C_SMBUS_READ, addr, REPEAT_START); + coldfire_read_data(&rxData, ACK); /* dummy read */ + /* Disable Acknowledge, generate STOP after next byte transfer */ + rc += coldfire_read_data(&rxData, NACK); + data->byte = rxData; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* reset to normal ACk */ + break; + case I2C_SMBUS_PROC_CALL: + case I2C_SMBUS_WORD_DATA: + dev_info(&adap->dev, "size = I2C_SMBUS_WORD_DATA \n"); + rc = coldfire_i2c_start(I2C_SMBUS_WRITE, addr, FIRST_START); + rc += coldfire_write_data(command); + if (read_write == I2C_SMBUS_WRITE) { + rc += coldfire_write_data(data->word & 0x00FF); + rc += coldfire_write_data((data->word & 0x00FF) >> 8); + } else { + /* This is SMBUS READ WORD request. Peform REPEAT START */ + rc += coldfire_i2c_start(I2C_SMBUS_READ, addr, REPEAT_START); + coldfire_read_data(&rxData, ACK); /* dummy read */ + /* Disable Acknowledge, generate STOP after next byte transfer */ + /* read the MS byte from the device */ + rc += coldfire_read_data(&rxData, NACK); + tempRxData[1] = rxData; + /* read the LS byte from the device */ + rc += coldfire_read_data(&rxData, NACK); + tempRxData[0] = rxData; + /* the host driver expect little endian convention. Swap the byte */ + data->word = (tempRxData[0] << 8) | tempRxData[1]; + } + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; + break; + case I2C_SMBUS_BLOCK_DATA: + /* this is not ready yet!!! + if (read_write == I2C_SMBUS_WRITE) { + dev_info(&adap->dev, "data = %.4x\n", data->word); + len = data->block[0]; + if (len < 0) + len = 0; + if (len > 32) + len = 32; + for (i = 1; i <= len; i++) + dev_info(&adap->dev, "data->block[%d] = %.2x\n", i, data->block[i]); + } */ + break; + default: + printk("Unsupported I2C size \n"); + rc = -1; + break; + }; + + /* Generate a STOP and put I2C module into slave mode */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + /* restore interrupt */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IIEN; + + if (rc < 0) + return -1; + else + return 0; +}; + + +/* + * List the SMBUS functions supported by this I2C adaptor + * Also tell the I2C Subsystem that we are able of master_xfer() + */ +static u32 coldfire_func(struct i2c_adapter *adapter) +{ + return(I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BLOCK_DATA); +}; + +static int coldfire_i2c_master(struct i2c_adapter *adap,struct i2c_msg *msgs, + int num) +{ + u8 dummyRead; + struct i2c_msg *p; + int i, err = 0; + int ic=0; + + lastaddr = 0; + lastop = 8; + + /* disable the IRQ, we are doing polling */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_IIEN; + + dev_dbg(&adap->dev,"Num of actions: %d\n", num); + + for (i = 0; !err && i < num; i++) { + p = &msgs[i]; + + + if (!p->len) + { + dev_dbg(&adap->dev,"p->len == 0!\n"); + continue; + } + /* + * Generate a new Start, if the target address differs from the last target, + * generate a stop in this case first + */ + if(p->addr != lastaddr) + { + err = coldfire_do_first_start(p->addr,p->flags); + if(err) + { + dev_dbg(&adap->dev,"First Init failed!\n"); + break; + } + } + + else if((p->flags & I2C_M_RD) != lastop) + { + /* + * If the Operational Mode changed, we need to do this here ... + */ + dev_dbg(&adap->dev,"%s(): Direction changed, was: %d; is now: %d\n", + __FUNCTION__,lastop,p->flags & I2C_M_RD); + + /* Last op was an read, now it's write: complete stop and reinit */ + if (lastop & I2C_M_RD) + { + dev_dbg(&adap->dev,"%s(): The device is in read state, we must reset!\n", + __FUNCTION__); + if((err = coldfire_do_first_start(p->addr,p->flags))) + break; + } + else + { + dev_dbg(&adap->dev,"%s(): We switchted to read mode\n",__FUNCTION__); + if((err = coldfire_i2c_start((p->flags & I2C_M_RD) ? I2C_SMBUS_READ : I2C_SMBUS_WRITE, + p->addr, REPEAT_START))) + break; + } + + lastop = p->flags & I2C_M_RD; /* Save the last op */ + } + + if (p->flags & I2C_M_RD) + { + /* + * When ever we get here, a new session was activated, so + * read a dummy byte + */ + coldfire_read_data(&dummyRead, ACK); + /* + * read p->len -1 bytes with ACK to the slave, + * read the last byte without the ACK, to inform him about the + * stop afterwards + */ + ic = 0; + while(!err && (ic < p->len-1 )) + { + err = coldfire_read_data(p->buf+ic, ACK ); + ic++; + } + if(!err) + err = coldfire_read_data(p->buf+ic, NACK); + dev_dbg(&coldfire_adapter.dev,"read: %2x\n", p->buf[ic]); + } + else + { + if(p->len == 2) + dev_dbg(&coldfire_adapter.dev,"writing: 0x %2x %2x\n", p->buf[0], p->buf[1]); + + /* + * Write data to the slave + */ + for(ic=0; !err && ic < p->len; ic++) + { + err = coldfire_write_data(p->buf[ic]); + if(err) + { + dev_dbg(&coldfire_adapter.dev,"Failed to write data\n"); + } + } + } + } + + /* + * Put the device into slave mode to enable the STOP Generation (the RTC needs this) + */ + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; + + *MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; /* reset the ACK bit */ + + /* restore interrupt */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IIEN; + + /* Return the number of messages processed, or the error code. */ + if (err == 0) + err = num; + return err; +} + + +/* + * Initalize the 5282 I2C module + * Disable the 5282 I2C interrupt capability. Just use callback + */ + +static int __init i2c_coldfire_init(void) +{ + int retval; + u8 dummyRead; + +#if defined(CONFIG_M532x) + /* + * Initialize the GPIOs for I2C + */ + MCF_GPIO_PAR_FECI2C |= (0 + | MCF_GPIO_PAR_FECI2C_PAR_SDA(3) + | MCF_GPIO_PAR_FECI2C_PAR_SCL(3)); +#else + /* Initialize PASP0 and PASP1 to I2C functions, 5282 user guide 26-19 */ + /* Port AS Pin Assignment Register (PASPAR) */ + /* PASPA1 = 11 = AS1 pin is I2C SDA */ + /* PASPA0 = 11 = AS0 pin is I2C SCL */ + *MCF_GPIO_PASPAR |= 0x000F; /* u16 declaration */ +#endif + + + /* Set transmission frequency 0x15 = ~100kHz */ + *MCF_I2C_I2FDR = 0x15; + + /* set the 5282 I2C slave address thought we never use it */ + *MCF_I2C_I2ADR = 0x6A; + + /* Enable I2C module and if IBB is set, do the special initialzation */ + /* procedures as are documented at the 5282 User Guide page 24-11 */ + *MCF_I2C_I2CR |= MCF_I2C_I2CR_IEN; + if ((*MCF_I2C_I2SR & MCF_I2C_I2SR_IBB) == 1) { + printk("%s - do special 5282 I2C init procedures \n", __FUNCTION__); + *MCF_I2C_I2CR = 0x00; + *MCF_I2C_I2CR = 0xA0; + dummyRead = *MCF_I2C_I2DR; + *MCF_I2C_I2SR = 0x00; + *MCF_I2C_I2CR = 0x00; + } + + /* default I2C mode is - slave and receive */ + *MCF_I2C_I2CR &= ~(MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_MTX); + + retval = i2c_add_adapter(&coldfire_adapter); + + if (retval < 0) + printk("%s - return code is: %d \n", __FUNCTION__, retval); + + return retval; +}; + + +/* + * I2C module exit function + */ + +static void __exit i2c_coldfire_exit(void) +{ + /* disable I2C and Interrupt */ + *MCF_I2C_I2CR &= ~(MCF_I2C_I2CR_IEN | MCF_I2C_I2CR_IIEN); + i2c_del_adapter(&coldfire_adapter); + +}; + + +MODULE_AUTHOR("Derek CL Cheung "); +MODULE_DESCRIPTION("MCF5282 I2C adaptor"); +MODULE_LICENSE("GPL"); + +module_init(i2c_coldfire_init); +module_exit(i2c_coldfire_exit); diff --git a/drivers/i2c/busses/i2c-mcf.h b/drivers/i2c/busses/i2c-mcf.h new file mode 100644 index 00000000..5714e7dc --- /dev/null +++ b/drivers/i2c/busses/i2c-mcf.h @@ -0,0 +1,52 @@ +/* + i2c-mcf5282.h - header file for i2c-mcf5282.c + + Copyright (c) 2005, Derek CL Cheung + + + Copyright (c) 2006, emlix and Freescale + Sebastian Hess + Yaroslav Vinogradov + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + v0.2 29 May 2006 + Modified to be more generic and added support for + i2c_master_xfer +*/ + + +#ifndef __I2C_MCF5282_H__ +#define __I2C_MCF5282_H__ + +enum I2C_START_TYPE { FIRST_START, REPEAT_START }; +enum I2C_ACK_TYPE { ACK, NACK}; + +/* Function prototypes */ +static u32 coldfire_func(struct i2c_adapter *adapter); +static s32 coldfire_i2c_access(struct i2c_adapter *adap, u16 address, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); +static int coldfire_write_data(const u8 data); +static int coldfire_i2c_start(const char read_write, const u16 target_address, const enum I2C_START_TYPE i2c_start); +static int coldfire_read_data(u8 * const rxData, const enum I2C_ACK_TYPE ackType); +static int coldfire_i2c_master(struct i2c_adapter *adap,struct i2c_msg *msgs, int num); +void dumpReg(char *, u16 addr, u8 data); + +/********************************************************************/ +#endif /* __I2C_MCF5282_H__ */ diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 87ee3ce5..e5ef30bc 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -110,6 +110,18 @@ config SENSORS_M41T00 This driver can also be built as a module. If so, the module will be called m41t00. +config SENSORS_M41T11 + tristate "ST M41T11 RTC chip" + depends on I2C + help + If you say yes here you get support for the ST M41T11 RTC chip. + + This driver also registers the miscellaneous RTC device, so + that you can use programs like hwclock on this RTC hardware. + + This driver can also be built as a module. If so, the module + will be called m41t11. + config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 779868ef..cbbde03a 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SENSORS_DS1374) += ds1374.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o +obj-$(CONFIG_SENSORS_M41T11) += m41t11.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o diff --git a/drivers/i2c/chips/m41t11.c b/drivers/i2c/chips/m41t11.c new file mode 100644 index 00000000..538a97a1 --- /dev/null +++ b/drivers/i2c/chips/m41t11.c @@ -0,0 +1,307 @@ +/* + * drivers/i2c/chips/m41t11.c + * + * I2C client driver for the ST M41T11 Real Time Clock chip. + * + * (C) Copyright (C) 2006, Greg Ungerer + */ + +/* + * This driver is very much a hybrid RTC and I2C driver. It has interfaces + * into both sub-systems (well the RTC is really a misc device). Ultimately + * I want to be able to use hwclock "as is" on the RTC. But the hardware is + * a true I2c device... + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define M41T11_DRV_NAME "m41t11" + +/* + * Size of RTC region. 64 bytes total, the first 10 are the RTC. + */ +#define M41T11_MSIZE 0x3f + +/* + * M41T11 register offsets. + */ +#define M41T11_SEC 0x00 /* Address of second register */ +#define M41T11_MIN 0x01 /* Address of minute register */ +#define M41T11_HOUR 0x02 /* Address of hour register */ +#define M41T11_WDAY 0x03 /* Address of day of week register */ +#define M41T11_MDAY 0x04 /* Address of day of month register */ +#define M41T11_MON 0x05 /* Address of month register */ +#define M41T11_YEAR 0x06 /* Address of year register */ +#define M41T11_FTOUT 0x07 /* Address of control register */ + +static DECLARE_MUTEX(m41t11_mutex); + +/* + * We keep a copy of the client device found, since we are really only + * need one device for the real misc device interface. + */ +static struct i2c_client *client; + +#define m41t11_readbyte(a) i2c_smbus_read_byte_data(client, a) +#define m41t11_writebyte(a,v) i2c_smbus_write_byte_data(client, a, v); + +/* + ***************************************************************************** + * + * RTC Driver Interface + * + ***************************************************************************** + */ + +static ssize_t m41t11_read(struct file *fp, char __user *buf, size_t count, loff_t *ptr) +{ + int total; + + if (fp->f_pos >= M41T11_MSIZE) + return 0; + + if (count > (M41T11_MSIZE - fp->f_pos)) + count = M41T11_MSIZE - fp->f_pos; + + down(&m41t11_mutex); + for (total = 0; (total < count); total++) + put_user(m41t11_readbyte(fp->f_pos + total), buf++); + up(&m41t11_mutex); + + fp->f_pos += total; + return total; +} + +static ssize_t m41t11_write(struct file *fp, const char __user *buf, size_t count, loff_t *ptr) +{ + int total; + char val; + + if (fp->f_pos >= M41T11_MSIZE) + return 0; + + if (count > (M41T11_MSIZE - fp->f_pos)) + count = M41T11_MSIZE - fp->f_pos; + + down(&m41t11_mutex); + for (total = 0; (total < count); total++, buf++) { + get_user(val,buf); + m41t11_writebyte((fp->f_pos + total), val); + } + up(&m41t11_mutex); + + fp->f_pos += total; + return total; +} + +/* + * Do some consistency checks on the time. On first power up the + * RTC may contain completely bogus junk, this will clean it up. + * Just for good measure we do this when writing to the RTC as well. + */ +static void m41t11_validatetime(struct rtc_time *rtime) +{ + if ((rtime->tm_year < 70) || (rtime->tm_year >= 200)) + rtime->tm_year = 70; + if ((rtime->tm_mon < 0) || (rtime->tm_mon >= 12)) + rtime->tm_mon = 0; + if ((rtime->tm_mday < 1) || (rtime->tm_mday > 31)) + rtime->tm_mday = 1; + if ((rtime->tm_wday < 0) || (rtime->tm_wday >= 7)) + rtime->tm_wday = 0; + if ((rtime->tm_hour < 0) || (rtime->tm_hour >= 24)) + rtime->tm_hour = 0; + if ((rtime->tm_min < 0) || (rtime->tm_min >= 60)) + rtime->tm_min = 0; + if ((rtime->tm_sec < 0) || (rtime->tm_sec >= 60)) + rtime->tm_sec = 0; +} + +static void m41t11_readtime(struct rtc_time *rtime) +{ + down(&m41t11_mutex); + memset(rtime, 0, sizeof(*rtime)); + rtime->tm_year = BCD2BIN(m41t11_readbyte(M41T11_YEAR)) + + ((m41t11_readbyte(M41T11_HOUR) & 0x40) ? 100 : 0); + rtime->tm_mon = BCD2BIN(m41t11_readbyte(M41T11_MON & 0x1f)) - 1; + rtime->tm_mday = BCD2BIN(m41t11_readbyte(M41T11_MDAY & 0x3f)); + rtime->tm_wday = BCD2BIN(m41t11_readbyte(M41T11_WDAY) & 0x7) - 1; + rtime->tm_hour = BCD2BIN(m41t11_readbyte(M41T11_HOUR) & 0x3f); + rtime->tm_min = BCD2BIN(m41t11_readbyte(M41T11_MIN) & 0x7f); + rtime->tm_sec = BCD2BIN(m41t11_readbyte(M41T11_SEC) & 0x7f); + up(&m41t11_mutex); +} + +static void m41t11_settime(struct rtc_time *rtime) +{ + down(&m41t11_mutex); + m41t11_writebyte(M41T11_YEAR, BIN2BCD(rtime->tm_year)); + m41t11_writebyte(M41T11_MON, BIN2BCD(rtime->tm_mon+1)); + m41t11_writebyte(M41T11_MDAY, BIN2BCD(rtime->tm_mday)); + m41t11_writebyte(M41T11_WDAY, BIN2BCD(rtime->tm_wday+1)); + m41t11_writebyte(M41T11_HOUR, BIN2BCD(rtime->tm_hour) | + ((rtime->tm_year > 99) ? 0xc0 : 0x80)); + m41t11_writebyte(M41T11_MIN, BIN2BCD(rtime->tm_min)); + m41t11_writebyte(M41T11_SEC, BIN2BCD(rtime->tm_sec)); + m41t11_writebyte(M41T11_FTOUT, 0x90); + up(&m41t11_mutex); +} + +static int m41t11_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct rtc_time rtime; + + switch (cmd) { + + case RTC_RD_TIME: + m41t11_readtime(&rtime); + m41t11_validatetime(&rtime); + if (copy_to_user((void __user *) arg, &rtime, sizeof(rtime))) + return -EFAULT; + break; + + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EACCES; + m41t11_validatetime(&rtime); + if (copy_from_user(&rtime, (void __user *) arg, sizeof(rtime))) + return -EFAULT; + m41t11_settime(&rtime); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + ***************************************************************************** + * + * I2C Driver Interface + * + ***************************************************************************** + */ + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .probe = ignore, + .ignore = ignore, +}; + +static struct i2c_driver m41t11_i2cdrv; + +static int m41t11_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *c; + int rc; + int val; + + c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!c) + return -ENOMEM; + + strncpy(c->name, M41T11_DRV_NAME, I2C_NAME_SIZE); + c->addr = addr; + c->adapter = adap; + c->driver = &m41t11_i2cdrv; + + if ((rc = i2c_attach_client(c)) != 0) { + kfree(c); + return rc; + } + + client = c; + + /* Start the oscillator if needed */ + val = m41t11_readbyte(M41T11_SEC); + if (val & 0x80) + m41t11_writebyte(M41T11_SEC, val & 0x7f); + + return 0; +} + +static int m41t11_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, m41t11_probe); +} + +static int m41t11_detach(struct i2c_client *c) +{ + int rc; + + if ((rc = i2c_detach_client(c)) < 0) + return rc; + kfree(c); + return 0; +} + +/* + ***************************************************************************** + * + * Driver Interface + * + ***************************************************************************** + */ + +static struct i2c_driver m41t11_i2cdrv = { + .driver = { + .name = M41T11_DRV_NAME, + }, + .id = I2C_DRIVERID_STM41T00, + .attach_adapter = m41t11_attach, + .detach_client = m41t11_detach, +}; + +static struct file_operations m41t11_fops = { + .owner = THIS_MODULE, + .read = m41t11_read, + .write = m41t11_write, + .ioctl = m41t11_ioctl, +}; + +static struct miscdevice m41t11_miscdrv = { + .minor = RTC_MINOR, + .name = "rtc", + .fops = &m41t11_fops, +}; + +static int __init m41t11_init(void) +{ + int rc; + + if ((rc = i2c_add_driver(&m41t11_i2cdrv)) < 0) + return rc; + if ((rc = misc_register(&m41t11_miscdrv)) < 0) { + i2c_del_driver(&m41t11_i2cdrv); + return rc; + } + + printk("M41T11: RTC I2C driver registered\n"); + return 0; +} + +static void __exit m41t11_exit(void) +{ + misc_deregister(&m41t11_miscdrv); + i2c_del_driver(&m41t11_i2cdrv); + return; +} + +module_init(m41t11_init); +module_exit(m41t11_exit); + +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("ST Microelectronics M41T11 RTC I2C Client Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 0c68d0f0..7ba38614 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -389,6 +389,13 @@ config BLK_DEV_RZ1000 Linux. This may slow disk throughput by a few percent, but at least things will operate 100% reliably. +config BLK_DEV_P20575 + tristate "Promise P20575 PATA interface" + depends on PCI && BLK_DEV_IDEPCI + help + This driver is for the PATA interface of the Promise 20575 + controller. + config BLK_DEV_SL82C105 tristate "Winbond SL82c105 support" depends on PCI && (PPC || ARM) && BLK_DEV_IDEPCI diff --git a/drivers/ide/arm/adi-coyote.c b/drivers/ide/arm/adi-coyote.c new file mode 100644 index 00000000..3e4a6e84 --- /dev/null +++ b/drivers/ide/arm/adi-coyote.c @@ -0,0 +1,104 @@ +/* + * drivers/ide/arm/adi-coyote.c + * + * IDE hooks for ADI Engineering Coyote platform + * + * Author: Deepak Saxena + * + * Copyright 2004 (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +static u16 coyote_inw(unsigned long p) +{ + return *((volatile u16 *)(COYOTE_IDE_BASE_VIRT + p)); +} + +static u8 coyote_inb(unsigned long p) +{ + return (u8) coyote_inw(p); +} + +static void coyote_insw(unsigned long port, void *addr, u32 count) +{ + while (count--) { + *(u16 *)addr = *(volatile u16 *)(COYOTE_IDE_BASE_VIRT + port); + addr += 2; + } +} +static void coyote_outw(u16 v, unsigned long p) +{ + *((volatile u16 *)(COYOTE_IDE_BASE_VIRT + p)) = v; +} + +static void coyote_outb(u8 v, unsigned long p) +{ + coyote_outw(v, p); +} + +static void coyote_outbsync(ide_drive_t *drive, u8 v, unsigned long p) +{ + coyote_outw(v, p); +} + +static void coyote_outsw(unsigned long port, void *addr, u32 count) +{ + while (count--) { + *(volatile u16 *)(COYOTE_IDE_BASE_VIRT + (port)) = *(u16 *)addr; + addr += 2; + } +} + +static int __init coyote_ide_init(void) +{ + int i; + struct hwif_s *hwifp; + hw_regs_t coyote_ide; + ide_ioreg_t reg = (ide_ioreg_t) COYOTE_IDE_DATA_PORT; + + if(!machine_is_adi_coyote()) + return -EIO; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + coyote_ide.io_ports[i] = reg; + reg += 2; + } + coyote_ide.irq = IRQ_COYOTE_IDE; + coyote_ide.io_ports[IDE_CONTROL_OFFSET] = COYOTE_IDE_CTRL_PORT; + coyote_ide.chipset = ide_generic; + + printk("Registering IDE HW: %d\n", + ide_register_hw(&coyote_ide, &hwifp)); + + /* + * Override the generic functions with our own implementation + */ + hwifp->OUTB = coyote_outb; + hwifp->OUTBSYNC = coyote_outbsync; + hwifp->OUTW = coyote_outw; + hwifp->OUTSW = coyote_outsw; + hwifp->INB = coyote_inb; + hwifp->INW = coyote_inw; + hwifp->INSW = coyote_insw; + + return 0; +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena "); +MODULE_DESCRIPTION("ADI Coyote IDE driver"); + +module_init(coyote_ide_init); + diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 2614f41b..3b4913dc 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1574,7 +1574,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) spin_lock_irqsave(&ide_lock, flags); hwif = hwgroup->hwif; - if (!ide_ack_intr(hwif)) { + if (hwif->hw.ack_intr && (hwif->hw.ack_intr(hwif) == 0)) { spin_unlock_irqrestore(&ide_lock, flags); return IRQ_NONE; } @@ -1614,6 +1614,10 @@ irqreturn_t ide_intr (int irq, void *dev_id) #endif /* CONFIG_BLK_DEV_IDEPCI */ } spin_unlock_irqrestore(&ide_lock, flags); +#if 1 + /* FIXME: otherwise we get "nobody cared?" messages */ + return IRQ_HANDLED; +#endif return IRQ_NONE; } drive = hwgroup->drive; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index dad9c47e..984aa824 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -55,6 +55,7 @@ #include #include + /** * generic_id - add a generic drive id * @drive: drive to make an ID block for @@ -876,10 +877,9 @@ static int hwif_init(ide_hwif_t *hwif); int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) { - probe_hwif(hwif); - if (fixup) fixup(hwif); + probe_hwif(hwif); if (!hwif_init(hwif)) { printk(KERN_INFO "%s: failed to initialize IDE interface\n", @@ -1026,7 +1026,6 @@ static int init_irq (ide_hwif_t *hwif) ide_hwgroup_t *hwgroup; ide_hwif_t *match = NULL; - BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); BUG_ON(hwif == NULL); diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index fef08960..eb0d0a4e 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o obj-$(CONFIG_BLK_DEV_PIIX) += piix.o obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o +obj-$(CONFIG_BLK_DEV_P20575) += p20575.o obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o diff --git a/drivers/ide/pci/p20575.c b/drivers/ide/pci/p20575.c new file mode 100644 index 00000000..8525a2c0 --- /dev/null +++ b/drivers/ide/pci/p20575.c @@ -0,0 +1,227 @@ +/* + * linux/drivers/ide/pci/p20575.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define PRINTK(x...) printk(x) +#else +#define PRINTK(x...) do { } while (0) +#endif + +#if 0 +static void hexdump(void *v, unsigned int len) +{ + unsigned int p = (unsigned int) v; + int i; + + for (i = 0; (i < (len/4)); i++) { + if ((i % 4) == 0) printk("%08x: ", (int)p); + printk("%08x ", readl(p)); + p += 4; + if (((i+1) % 4) == 0) printk("\n"); + } + if ((i % 4) != 0) printk("\n"); +} +#endif + +void *p20575_iomap; + +static u8 p20575_inb(unsigned long port) +{ + u8 v; + PRINTK("p20575_inb(port=%x)", (int)port); + v = readl(p20575_iomap+port); + PRINTK("=%x\n", (int)v); + return v; +} + +static u16 p20575_inw(unsigned long port) +{ + u16 v; + PRINTK("p20575_inw(port=%x)", (int)port); + v = readl(p20575_iomap+port); + PRINTK("=%x\n", (int)v); + return v; +} + +static u32 p20575_inl(unsigned long port) +{ + u32 v; + PRINTK("p20575_inl(port=%x)", (int)port); + v = readl(p20575_iomap+port); + PRINTK("=%x\n", (int)v); + return v; +} + +static void p20575_outb(u8 val, unsigned long port) +{ + PRINTK("p20575_outb(val=%x,port=%x)\n", (int)val, (int)port); + writel(val, p20575_iomap+port); +} + +static void p20575_outbsync(ide_drive_t *drive, u8 val, unsigned long port) +{ + PRINTK("p20575_outb(val=%x,port=%x)\n", (int)val, (int)port); + writel(val, p20575_iomap+port); +} + +static void p20575_outw(u16 val, unsigned long port) +{ + PRINTK("p20575_outw(val=%x,port=%x)\n", (int)val, (int)port); + writel(val, p20575_iomap+port); +} + +static void p20575_outl(u32 val, unsigned long port) +{ + PRINTK("p20575_outl(val=%x,port=%x)\n", (int)val, (int)port); + writel(val, p20575_iomap+port); +} + +static void p20575_outsw(unsigned long port, void *buf, u32 len) +{ + u16 w, *wp = buf; + PRINTK("p20575_outsw(port=%x,buf=%x,len=%x)\n", (int)port, (int)buf, len); + while (len--) { + w = *wp++; + w = (w << 8) | (w >> 8); + writel(w, p20575_iomap+port); + } +} + +static void p20575_insw(unsigned long port, void *buf, u32 len) +{ + u16 w, *wp = buf; + PRINTK("p20575_insw(port=%x,buf=%x,len=%x)\n", (int)port, (int)buf, len); + while (len--) { + w = readl(p20575_iomap+port); + *wp++ = (w << 8) | (w >> 8); + } +} + +static int p20575_ack_intr(ide_hwif_t *hwif) +{ + unsigned int v; + + v = readl(p20575_iomap+0x40); + writel(v, p20575_iomap+0x40); + writel(1, p20575_iomap+(2*4)); + return 1; +} + +static void __devinit p20575_init_iops(ide_hwif_t *hwif) +{ + hw_regs_t hw; + + PRINTK("%s(%d): p20575_init_iops()\n", __FILE__, __LINE__); + + memset(&hw, 0, sizeof(hw)); + hw.io_ports[IDE_DATA_OFFSET] = 0x300; + hw.io_ports[IDE_ERROR_OFFSET] = 0x304; + hw.io_ports[IDE_NSECTOR_OFFSET] = 0x308; + hw.io_ports[IDE_SECTOR_OFFSET] = 0x30c; + hw.io_ports[IDE_LCYL_OFFSET] = 0x310; + hw.io_ports[IDE_HCYL_OFFSET] = 0x314; + hw.io_ports[IDE_SELECT_OFFSET] = 0x318; + hw.io_ports[IDE_STATUS_OFFSET] = 0x31C; + hw.io_ports[IDE_CONTROL_OFFSET] = 0x338; + hw.irq = hwif->pci_dev->irq; + hw.ack_intr = p20575_ack_intr; + + hwif->INB = p20575_inb; + hwif->INW = p20575_inw; + hwif->INL = p20575_inl; + hwif->OUTB = p20575_outb; + hwif->OUTBSYNC = p20575_outbsync; + hwif->OUTW = p20575_outw; + hwif->OUTL = p20575_outl; + hwif->OUTSW = p20575_outsw; + hwif->INSW = p20575_insw; + + hwif->mmio = 2; + + memcpy(&hwif->hw, &hw, sizeof(hw)); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); +} + +static unsigned int __devinit p20575_init_chipset(struct pci_dev *dev, const char *name) +{ + PRINTK("%s(%d): p20575_init_chipset(name=%s) -> irq=%d\n", __FILE__, __LINE__, name, dev->irq); + + p20575_iomap = ioremap(0x48060000, 0x1000); + PRINTK("%s(%d): iomap=%x\n", __FILE__, __LINE__, (int)p20575_iomap); + + writel(2, p20575_iomap+0x360); + writel(1, p20575_iomap+(2*4)); + + return dev->irq; +} + +static void __devinit p20575_init_hwif(ide_hwif_t *hwif) +{ + PRINTK("%s(%d): p20575_init_hwif()\n", __FILE__, __LINE__); + + hwif->autodma = 0; + hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; +} + +static int __devinit p20575_init_setup(struct pci_dev *dev, ide_pci_device_t *d) +{ + PRINTK("%s(%d): p20575_init_setup()\n", __FILE__, __LINE__); + return ide_setup_pci_device(dev, d); +} + +static ide_pci_device_t p20575_chipset __devinitdata = { + .name = "P20575", + .init_setup = p20575_init_setup, + .init_chipset = p20575_init_chipset, + .init_iops = p20575_init_iops, + .init_hwif = p20575_init_hwif, + .channels = 1, + .autodma = AUTODMA, + .bootable = ON_BOARD, + .flags = IDEPCI_FLAG_ISA_PORTS, +}; + +static int __devinit p20575_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + PRINTK("%s(%d): p20575_init_one()\n", __FILE__, __LINE__); + return p20575_chipset.init_setup(dev, &p20575_chipset); +} + +static struct pci_device_id p20575_pci_tbl[] = { + { PCI_VENDOR_ID_PROMISE, 0x3575, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, p20575_pci_tbl); + +static struct pci_driver driver = { + .name = "P20575-IDE", + .id_table = p20575_pci_tbl, + .probe = p20575_init_one, +}; + +static int p20575_ide_init(void) +{ + PRINTK("%s(%d): p20575_ide_init()\n", __FILE__, __LINE__); + return ide_pci_register_driver(&driver); +} + +module_init(p20575_ide_init); + +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("PCI driver module for PATA channel of Promise 20575"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c index c68f328e..e942109f 100644 --- a/drivers/ieee1394/dma.c +++ b/drivers/ieee1394/dma.c @@ -34,7 +34,11 @@ int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, prog->n_pages = n_bytes >> PAGE_SHIFT; +#ifdef CONFIG_PCI prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr); +#else + prog->kvirt = kmalloc(n_bytes, in_interrupt()? GFP_ATOMIC: GFP_KERNEL); +#endif if (!prog->kvirt) { printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n"); @@ -50,8 +54,12 @@ int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, void dma_prog_region_free(struct dma_prog_region *prog) { if (prog->kvirt) { +#ifdef CONFIG_PCI pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT, prog->kvirt, prog->bus_addr); +#else + kfree(prog->kvirt); +#endif } prog->kvirt = NULL; @@ -110,8 +118,15 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, } /* map sglist to the IOMMU */ +#ifdef CONFIG_PCI dma->n_dma_pages = pci_map_sg(dev, dma->sglist, dma->n_pages, direction); +#else + dma->n_dma_pages = dma->n_pages; + for (i = 0; i < dma->n_pages; i++) { + dma->sglist[i].dma_address = virt_to_bus(page_address(dma->sglist[i].page)); + } +#endif if (dma->n_dma_pages == 0) { printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n"); @@ -131,8 +146,10 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, void dma_region_free(struct dma_region *dma) { if (dma->n_dma_pages) { +#ifdef CONFIG_PCI pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction); +#endif dma->n_dma_pages = 0; dma->dev = NULL; } @@ -180,6 +197,7 @@ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma, void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len) { +#ifdef CONFIG_PCI int first, last; unsigned long rem = 0; @@ -191,11 +209,13 @@ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); +#endif } void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len) { +#ifdef CONFIG_PCI int first, last; unsigned long rem = 0; @@ -207,6 +227,7 @@ void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); +#endif } #ifdef CONFIG_MMU diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ea41852e..41f33e4b 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -125,4 +125,14 @@ config MMC_TIFM_SD To compile this driver as a module, choose M here: the module will be called tifm_sd. +config MMC_MOXART + tristate "Moxa CPU SD/Multimedia Card Interface support" + depends on ARCH_MOXART && MMC + help + This selects the Moxa(R) CPU(R) SD/Multimedia card Interface. + If you have a Moxa(R) CPU platform with a SD/Multimedia Card slot, + say Y or M here. + + If unsure, say N. + endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index acfd4de0..b37adc3f 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o +obj-$(CONFIG_MMC_MOXART) += moxasd.o mmc_core-y := mmc.o mmc_sysfs.o mmc_core-$(CONFIG_BLOCK) += mmc_queue.o diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 766bc544..31e827b6 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -486,6 +486,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return ocr; } +#if 0 // mask by Victor Yu. 03-07-2007 #define UNSTUFF_BITS(resp,start,size) \ ({ \ const int __size = size; \ @@ -499,6 +500,21 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) __res |= resp[__off-1] << ((32 - __shft) % 32); \ __res & __mask; \ }) +#else +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const int __size = size; \ + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ + const int __off = ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off+1] << ((32 - __shft) % 32); \ + __res & __mask; \ + }) +#endif /* * Given the decoded CSD structure, decode the raw CID to our CID structure. diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index f9027c8d..35075561 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,9 @@ #include #include +#ifdef CONFIG_ARCH_UC7101 +#include +#endif #include "mmc_queue.h" @@ -45,7 +49,11 @@ */ #define MMC_SHIFT 3 +#if 0 // mask by Victor Yu. 03-07-2007 static int major; +#else +static int major=121; +#endif /* * There is one mmc_blk_data per slot. @@ -94,10 +102,18 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) struct mmc_blk_data *md; int ret = -ENXIO; +#if 0 // mask by Victor Yu. 03-07-2007 md = mmc_blk_get(inode->i_bdev->bd_disk); +#else + md = mmc_blk_get(inode->u.i_bdev->bd_disk); +#endif if (md) { if (md->usage == 2) +#if 0 // mask by Victor Yu. 03-07-2007 check_disk_change(inode->i_bdev); +#else + check_disk_change(inode->u.i_bdev); +#endif ret = 0; if ((filp->f_mode & FMODE_WRITE) && md->read_only) @@ -109,7 +125,11 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) static int mmc_blk_release(struct inode *inode, struct file *filp) { +#if 0 // mask by Victor Yu. 03-07-2007 struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data; +#else + struct mmc_blk_data *md = inode->u.i_bdev->bd_disk->private_data; +#endif mmc_blk_put(md); return 0; @@ -283,7 +303,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_wait_for_req(card->host, &brq.mrq); if (brq.cmd.error) { - printk(KERN_ERR "%s: error %d sending read/write command\n", + printk(KERN_ERR "%s: victor error %d sending read/write command\n", req->rq_disk->disk_name, brq.cmd.error); goto cmd_err; } @@ -512,6 +532,42 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) return 0; } +#if 1 // add by Victor Yu. 03-07-2007 +#ifdef CONFIG_ARCH_UC7101 +#define SD_LED (1<<30) +#endif +static void moxa_pnp(int status) +{ + char *argv[3] , *envp[4] ; + + envp[0] = "HOME=/" ; + envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin" ; + envp[2] = "TERM=console" ; + envp[3] = NULL ; + + argv[0] = "pnp" ; + argv[2] = NULL ; + + if(status) { + argv[1] = "mount" ; + if(call_usermodehelper("/bin/pnp",argv,envp,0)==-1) + printk("execute mount failure\n") ; +#ifdef CONFIG_ARCH_UC7101 + else + mcpu_gpio_set(SD_LED, MCPU_GPIO_LOW); +#endif + } else { + argv[1] = "umount" ; + if(call_usermodehelper("/bin/pnp",argv,envp,0)==-1) + printk("execute umount failure\n") ; +#ifdef CONFIG_ARCH_UC7101 + else + mcpu_gpio_set(SD_LED, MCPU_GPIO_HIGH); +#endif + } +} +#endif + static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; @@ -538,6 +594,9 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_set_drvdata(card, md); add_disk(md->disk); +#if 1 // add by Victor Yu. 03-07-2007 + moxa_pnp(1); +#endif return 0; out: @@ -566,6 +625,9 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_blk_put(md); } mmc_set_drvdata(card, NULL); +#if 1 // add by Victor Yu. 03-07-2007 + moxa_pnp(0); +#endif } #ifdef CONFIG_PM diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 10cc9734..d3074173 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -254,7 +254,11 @@ static struct class mmc_host_class = { }; static DEFINE_IDR(mmc_host_idr); +#if 0 // mask by Victor Yu. 03-07-2007 static DEFINE_SPINLOCK(mmc_host_lock); +#else +static spinlock_t mmc_host_lock=SPIN_LOCK_UNLOCKED; +#endif /* * Internal function. Allocate a new MMC host. diff --git a/drivers/mmc/moxasd.c b/drivers/mmc/moxasd.c new file mode 100644 index 00000000..1a94903c --- /dev/null +++ b/drivers/mmc/moxasd.c @@ -0,0 +1,736 @@ +/* + * linux/drivers/mmc/moxasd.c - Moxa CPU SD/MMC driver + * + * Copyright (C) 2005 Moxa Tech., All Rights Reserved. + * + * 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. + * + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 +#include +#else +#include +#endif // LINUX_VERSION_CODE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "moxasd.h" + +#if 0 // mask by Victor Yu. 03-19-2007 +#define MSD_RETRY_COUNT 1000 +#else +#define MSD_RETRY_COUNT 100 +#endif +//#define CONFIG_MMC_DEBUG +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct moxasd_host { + struct mmc_host *mmc; + spinlock_t lock; + moxasd_reg *reg; + apb_dma_priv *dma; +#ifdef MSD_SUPPORT_GET_CLOCK + unsigned int sysclk; +#endif + struct mmc_request *mrq; + struct mmc_data *data; + + struct scatterlist *cur_sg; /* Current SG entry */ + unsigned int num_sg; /* Number of entries left */ + void *mapped_sg; /* vaddr of mapped sg */ + unsigned int remain; /* Data left in curren entry */ + int size; /* Total size of transfer */ + + struct tasklet_struct card_change_tasklet; + struct tasklet_struct fifo_run_tasklet; +}; + +static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data) +{ + /* + * Get info. about SG list from data structure. + */ + host->cur_sg = data->sg; + host->num_sg = data->sg_len; + + host->remain = host->cur_sg->length; +#if 1 // add by Victor Yu. 07-04-2007 + if ( host->remain > host->size ) + host->remain = host->size; + host->mapped_sg = NULL; +#endif + data->error = MMC_ERR_NONE; +} + +static inline int moxasd_next_sg(struct moxasd_host* host) +{ +#if 1 // add by Victor Yu. 07-04-2007 + struct mmc_data *data=host->data; +#endif + /* + * Skip to next SG entry. + */ + host->cur_sg++; + host->num_sg--; + + /* + * Any entries left? + */ + if (host->num_sg > 0) { + host->remain = host->cur_sg->length; +#if 1 // add by Victor Yu. 07-04-2007 + { + int remain; + remain = host->size - data->bytes_xfered; + if ( remain > 0 && remain < host->remain ) { + host->remain = remain; + } + } +#endif + } + + return host->num_sg; +} + +static inline char *moxasd_kmap_sg(struct moxasd_host* host) +{ + host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ); + return host->mapped_sg + host->cur_sg->offset; +} + +static void moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data) +{ + char *buffer; + int wcnt, i; + +#if 1 // add by Victor Yu. 07-06-2007 + if ( host->mapped_sg ) { + kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + moxasd_next_sg(host); + } +#endif + if ( host->size == data->bytes_xfered ) { + return; + } + buffer = moxasd_kmap_sg(host); + if ( host->size > MSD_FIFO_LENB && host->dma ) { + apb_dma_conf_param param; + param.size = host->remain; + param.burst_mode = APB_DMAB_BURST_MODE; + param.data_width = APB_DMAB_DATA_WIDTH_4; + if ( data->flags & MMC_DATA_WRITE ) { + param.source_addr = (unsigned int)buffer; + param.dest_addr = (unsigned int)&host->reg->data_window; + param.dest_inc = APB_DMAB_DEST_INC_0; + param.source_inc = APB_DMAB_DEST_INC_4_16; + param.dest_sel = APB_DMAB_DEST_APB; + param.source_sel = APB_DMAB_SOURCE_AHB; + } else { + param.dest_addr = (unsigned int)buffer; + param.source_addr = (unsigned int)&host->reg->data_window; + param.source_inc = APB_DMAB_DEST_INC_0; + param.dest_inc = APB_DMAB_DEST_INC_4_16; + param.source_sel = APB_DMAB_DEST_APB; + param.dest_sel = APB_DMAB_SOURCE_AHB; + } + data->bytes_xfered += host->remain; + apb_dma_conf(host->dma, ¶m); + apb_dma_enable(host->dma); + } else { + wcnt = host->remain >> 2; + if ( data->flags & MMC_DATA_WRITE ) { + for ( i=0; ireg->data_window); + } else { + for ( i=0; ireg->data_window); + } + wcnt <<= 2; + host->remain -= wcnt; + data->bytes_xfered += wcnt; + } +} + +static void moxasd_request_done(struct moxasd_host *host) +{ + struct mmc_request *mrq=host->mrq; + + if ( mrq == NULL ) { + return; + } + host->mrq = NULL; + host->data = NULL; + mmc_request_done(host->mmc, mrq); +} + +static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data) +{ + unsigned int timeout, datactrl; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + int blksz_bits; +#endif // LINUX_VERSION_CODE + + host->data = data; + // initialize the data size +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + host->size = data->blocks * data->blksz; + blksz_bits = ffs(data->blksz) - 1; + BUG_ON(1 << blksz_bits != data->blksz); +#else + host->size = data->blocks << data->blksz_bits; +#endif // LINUX_VERSION_CODE + moxasd_init_sg(host, data); + + // initialize the timeout value + timeout = (host->mmc->f_max/1000) * (data->timeout_ns/1000); + timeout *= 2; + + // initialize the data control +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + datactrl = (blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN; +#else + datactrl = (data->blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN; +#endif // LINUX_VERSION_CODE + if ( data->flags & MMC_DATA_WRITE ) { + datactrl |= MSD_DATA_WRITE; + } + if ( host->size > MSD_FIFO_LENB && host->dma ) { + datactrl |= MSD_DMA_EN; + } + writel(timeout, &host->reg->data_timer); + writel(host->size, &host->reg->data_length); + writel(datactrl, &host->reg->data_control); + + if ( host->size > MSD_FIFO_LENB && host->dma ) { + writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); + moxasd_do_fifo(host, data); + //tasklet_schedule(&host->fifo_run_tasklet); + } else { + writel(MSD_INT_FIFO_URUN|MSD_INT_FIFO_ORUN|MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); + } +} + +static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd) +{ + unsigned int status, cmdctrl; + int retry=0; + +#if 1 // add by Victor Yu. 03-19-2007 + cmd->error = MMC_ERR_TIMEOUT; +#endif + + // first clear status + writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear); + + // write argument + writel(cmd->arg, &host->reg->argument); + + // write command + cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK; + if ( cmdctrl == SD_APP_SET_BUS_WIDTH || + cmdctrl == SD_APP_OP_COND || + cmdctrl == SD_APP_SEND_SCR ) // this is SD application specific command + cmdctrl |= MSD_APP_CMD; + if ( cmd->flags & MMC_RSP_LONG ) + cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP); + if ( cmd->flags & MMC_RSP_SHORT ) + cmdctrl |= MSD_NEED_RSP; + writel(cmdctrl|MSD_CMD_EN, &host->reg->command); + + // wait response + while ( retry++ < MSD_RETRY_COUNT ) { + status = readl(&host->reg->status); + if ( status & MSD_CARD_DETECT ) { // card is removed + cmd->error = MMC_ERR_TIMEOUT; + break; + } + if ( cmdctrl & MSD_NEED_RSP ) { + if ( status & MSD_RSP_TIMEOUT ) { + writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear); + cmd->error = MMC_ERR_TIMEOUT; + break; + } +#if 0 + if ( status & MSD_RSP_CRC_FAIL ) { +#else + if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) { +#endif + writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear); + cmd->error = MMC_ERR_BADCRC; + break; + } + if ( status & MSD_RSP_CRC_OK ) { + writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear); + // read response + cmd->resp[0] = readl(&host->reg->response0); + cmd->resp[1] = readl(&host->reg->response1); + cmd->resp[2] = readl(&host->reg->response2); + cmd->resp[3] = readl(&host->reg->response3); + cmd->error = MMC_ERR_NONE; + break; + } + } else { + if ( status & MSD_CMD_SENT ) { + writel(MSD_CLR_CMD_SENT, &host->reg->clear); + cmd->error = MMC_ERR_NONE; + break; + } + } + } +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static irqreturn_t moxasd_irq(int irq, void *devid) +#else +static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs) +#endif // LINUX_VERSION_CODE +{ + struct moxasd_host *host=devid; + unsigned int status; + + // get the interrupt status + status = readl(&host->reg->status); + + // acknowledge the interurpt + if ( status & MSD_CARD_CHANGE ) { // has card inserted or removed + //writel(MSD_CLR_CARD_CHANGE, &host->reg->clear); + tasklet_schedule(&host->card_change_tasklet); + } + + if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) { + writel(status&(MSD_FIFO_ORUN|MSD_FIFO_URUN), &host->reg->clear); + tasklet_schedule(&host->fifo_run_tasklet); + } + + return IRQ_HANDLED; +} + +static void moxasd_fifo_run(unsigned long param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + struct mmc_data *data; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host = (struct moxasd_host *)param; + data = host->data; + if ( host->mrq == NULL || data == NULL ) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + moxasd_do_fifo(host, data); + if ( host->size == data->bytes_xfered ) { +#if 1 // mask by Victor Yu. 07-04-2007 + unsigned int status; + while ( 1 ) { + status = readl(&host->reg->status); + if ( status & (MSD_DATA_CRC_OK|MSD_DATA_CRC_FAIL|MSD_DATA_END) ) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(5); + } + if ( status & MSD_DATA_CRC_OK ) { + writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear); + } + if ( status & MSD_DATA_CRC_FAIL ) { + writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear); + data->error = MMC_ERR_TIMEOUT; + } + if ( status & MSD_DATA_END ) { + writel(MSD_CLR_DATA_END, &host->reg->clear); + } +#endif + if ( data->stop ) { + moxasd_send_command(host, data->stop); + } + } else { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + moxasd_request_done(host); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void moxasd_card_change(unsigned long param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + unsigned int status; + int delay; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + udelay(1000); + udelay(1000); + udelay(1000); +#else + udelay(3000); +#endif // LINUX_VERSION_CODE + status = readl(&host->reg->status); + if ( status & MSD_CARD_DETECT ) { // card removed + printk("Moxa CPU SD/MMC card is removed.\n"); + delay = 0; + if ( host->data ) { + if ( host->dma && host->size > MSD_FIFO_LENB ) + apb_dma_disable(host->dma); + host->size = host->data->bytes_xfered; + moxasd_fifo_run(*(unsigned long *)host); + host->data->error = MMC_ERR_TIMEOUT; + moxasd_request_done(host); + } + } else { // card inserted + printk("Moxa CPU SD/MMC card is inserted.\n"); + if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // SD + host->mmc->f_max = 25000000; + host->mmc->mode = MMC_MODE_SD; + } else { + host->mmc->f_max = 20000000; + host->mmc->mode = MMC_MODE_MMC; + } + delay = 500; + } + writel(MSD_CLR_CARD_CHANGE, &host->reg->clear); + spin_unlock_irqrestore(&host->lock, flags); + mmc_detect_change(host->mmc, msecs_to_jiffies(delay)); +} + +static void moxasd_dma_irq(void *param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + + if ( host ) + tasklet_schedule(&host->fifo_run_tasklet); +} + +static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct moxasd_host *host=mmc_priv(mmc); + struct mmc_command *cmd; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->mrq = mrq; + cmd = mrq->cmd; + + // if no card inserted, return timeout error + if ( readl(&host->reg->status) & MSD_CARD_DETECT ) { // card is removed + cmd->error = MMC_ERR_TIMEOUT; + goto request_done; + } + + // request include data or not + if ( cmd->data ) { + moxasd_prepare_data(host, cmd->data); + } + + // do request command + moxasd_send_command(host, cmd); + + if ( cmd->data && cmd->error == MMC_ERR_NONE ) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + +request_done: + moxasd_request_done(host); + spin_unlock_irqrestore(&host->lock, flags); +} + +#define MIN_POWER (MMC_VDD_360 - MSD_SD_POWER_MASK) +static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct moxasd_host *host=mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (ios->clock) { + int div; +#ifdef MSD_SUPPORT_GET_CLOCK + div = (host->sysclk / (host->mmc->f_max * 2)) - 1; +#else + div = (APB_CLK / (host->mmc->f_max * 2)) - 1; +#endif + if ( div > MSD_CLK_DIV_MASK ) + div = MSD_CLK_DIV_MASK; + else if ( div < 0 ) + div = 0; + if ( host->mmc->mode == MMC_MODE_SD ) + div |= MSD_CLK_SD; + writel(div, &host->reg->clock_control); + } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) { + /* + * Ensure that the clock is off. + */ + writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control); + } + + if ( ios->power_mode == MMC_POWER_OFF ) { + writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control); + } else { + unsigned short power; + if ( ios->vdd < MIN_POWER ) + power = 0; + else + power = ios->vdd - MIN_POWER; + writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control); + } + +#if 1 + if ( ios->bus_width == MMC_BUS_WIDTH_1 ) { + writel(MSD_SINGLE_BUS, &host->reg->bus_width); + } else { + writel(MSD_WIDE_BUS, &host->reg->bus_width); + } +#endif + spin_unlock_irqrestore(&host->lock, flags); +} + +/* + * To check write protect or not. Return 0 for none, 1 for write protect. + */ +static int moxasd_get_ro(struct mmc_host *mmc) +{ + struct moxasd_host *host=mmc_priv(mmc); + + if ( readl(&host->reg->status) & MSD_WRITE_PROT ) + return 1; + else + return 0; +} + +static struct mmc_host_ops moxasd_ops = { + .request = moxasd_request, + .set_ios = moxasd_set_ios, + .get_ro = moxasd_get_ro, +}; + +static int moxasd_probe(struct device *dev) +{ + struct mmc_host *mmc; + struct moxasd_host *host=NULL; + int ret; + + mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + mmc->ops = &moxasd_ops; + mmc->f_min = 400000; + mmc->f_max = 25000000; + mmc->mode = MMC_MODE_SD; +#if 1 + mmc->ocr_avail = 0xffff00; // support 2.0v - 3.6v power +#else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->max_hw_segs = 128; + mmc->max_phys_segs = 128; + mmc->max_sectors = 128; + mmc->max_seg_size = mmc->max_sectors * 512; +#endif + + host = mmc_priv(mmc); + host->mmc = mmc; + spin_lock_init(&host->lock); + tasklet_init(&host->card_change_tasklet, moxasd_card_change, (unsigned long)host); + tasklet_init(&host->fifo_run_tasklet, moxasd_fifo_run, (unsigned long)host); + host->reg = (moxasd_reg *)CPE_SD_BASE; + host->dma = apb_dma_alloc(APB_DMA_SD_REQ_NO); + if ( host->dma ) { + apb_dma_set_irq(host->dma, moxasd_dma_irq, host); + } + +#ifdef MSD_SUPPORT_GET_CLOCK + // get system clock + { + unsigned int mul, val, div; + mul = (*(volatile unsigned int *)(CPE_PMU_BASE+0x30) >> 3) & 0x1ff; + val = (*(volatile unsigned int *)(CPE_PMU_BASE+0x0c) >> 4) & 0x7; + switch ( val ) { + case 0 : div = 2; break; + case 1 : div = 3; break; + case 2 : div = 4; break; + case 3 : div = 6; break; + case 4 : div = 8; break; + default : div = 2; break; + } + host->sysclk = (38684*mul + 10000) / (div * 10000); + host->sysclk = (host->sysclk * 1000000) / 2; + } +#endif + + // change I/O multiplexing to SD, so the GPIO 17-10 will be fail + mcpu_gpio_mp_clear(0xff<<10); +#ifdef CONFIG_ARCH_UC7101 +#define SD_LED (1<<30) + mcpu_gpio_mp_set(SD_LED); + mcpu_gpio_inout(SD_LED, MCPU_GPIO_OUTPUT); + mcpu_gpio_set(SD_LED, MCPU_GPIO_HIGH); +#endif + + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + writel(0, &host->reg->interrupt_mask); // disable all interrupt + writel(MSD_SDC_RST, &host->reg->command); // reset chip + while ( readl(&host->reg->command) & MSD_SDC_RST); // wait for reset finished + writel(0, &host->reg->interrupt_mask); // disable all interrupt + + // to check any card inserted or not + if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted + if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // is SD card + mmc->f_max = 25000000; + mmc->mode = MMC_MODE_SD; + } else { // is MMC card + mmc->f_max = 20000000; + mmc->mode = MMC_MODE_MMC; + } + } + + mmc->caps = MMC_CAP_4_BIT_DATA; + writel(MSD_WIDE_BUS, &host->reg->bus_width); + + cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE); + ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host); + if (ret) + goto out; + + //writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask); + writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); + dev_set_drvdata(dev, mmc); + mmc_add_host(mmc); + + return 0; + + out: + if (mmc) + mmc_free_host(mmc); + + return ret; +} + +static int moxasd_remove(struct device *dev) +{ + struct mmc_host *mmc=dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (mmc) { + struct moxasd_host *host=mmc_priv(mmc); + + mmc_remove_host(mmc); + + // stop SD/MMC + if ( host->dma ) { + apb_dma_disable(host->dma); + apb_dma_release_irq(host->dma); + apb_dma_release(host->dma); + } + writel(0, &host->reg->interrupt_mask); + writel(0, &host->reg->power_control); + writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control); + + free_irq(IRQ_SD, host); + tasklet_kill(&host->card_change_tasklet); + tasklet_kill(&host->fifo_run_tasklet); + + mmc_free_host(mmc); + } + return 0; +} + +static struct platform_device moxasd_device = { + .name = "moxart-sd", + .id = -1, +}; + +static struct device_driver moxasd_driver = { + .name = "moxart-sd", + .bus = &platform_bus_type, + .probe = moxasd_probe, + .remove = moxasd_remove, +}; + +#if 1 // add by Victor Yu. 03-08-2007 +extern int moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c +#endif +static int __init moxasd_init(void) +{ + int ret; + + printk("Moxa CPU SD/MMC Device Driver V1.0 initialize "); +#if 1 // add by Victor Yu. 03-08-2007 + { + unsigned long flags; + local_irq_save(flags); + if ( moxa_gpio_sd_used_flag ) { + printk("The IO has used by other device driver !\n"); + local_irq_restore(flags); + return -ENODEV; + } + moxa_gpio_sd_used_flag = 1; + local_irq_restore(flags); + } +#endif + platform_device_register(&moxasd_device); + ret = driver_register(&moxasd_driver); + if ( ret ) { + printk("Modules load fail !\n"); + platform_device_unregister(&moxasd_device); + } else { + printk("Modules load OK.\n"); + } + return ret; +} + +static void __exit moxasd_exit(void) +{ + platform_device_unregister(&moxasd_device); + driver_unregister(&moxasd_driver); +#if 1 // add by Victor Yu. 12-05-2007 + { + unsigned long flags; + local_irq_save(flags); + moxa_gpio_sd_used_flag = 0; + local_irq_restore(flags); + } +#endif +} + +module_init(moxasd_init); +module_exit(moxasd_exit); + +MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/moxasd.c-bak-07122007 b/drivers/mmc/moxasd.c-bak-07122007 new file mode 100644 index 00000000..4d8d0769 --- /dev/null +++ b/drivers/mmc/moxasd.c-bak-07122007 @@ -0,0 +1,836 @@ +/* + * linux/drivers/mmc/moxasd.c - Moxa CPU SD/MMC driver + * + * Copyright (C) 2005 Moxa Tech., All Rights Reserved. + * + * 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. + * + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 +#include +#else +#include +#endif // LINUX_VERSION_CODE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "moxasd.h" + +#if 0 // mask by Victor Yu. 03-19-2007 +#define MSD_RETRY_COUNT 1000 +#else +#define MSD_RETRY_COUNT 100 +#endif +//#define CONFIG_MMC_DEBUG +#ifdef CONFIG_MMC_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +struct moxasd_host { + struct mmc_host *mmc; + spinlock_t lock; + moxasd_reg *reg; + apb_dma_priv *dma; +#ifdef MSD_SUPPORT_GET_CLOCK + unsigned int sysclk; +#endif + struct mmc_request *mrq; + struct mmc_data *data; + + struct scatterlist *cur_sg; /* Current SG entry */ + unsigned int num_sg; /* Number of entries left */ + void *mapped_sg; /* vaddr of mapped sg */ + unsigned int offset; /* Offset into current entry */ + unsigned int remain; /* Data left in curren entry */ + int size; /* Total size of transfer */ + + struct tasklet_struct card_change_tasklet; + struct tasklet_struct fifo_run_tasklet; +}; + +static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data) +{ + /* + * Get info. about SG list from data structure. + */ + host->cur_sg = data->sg; + host->num_sg = data->sg_len; + + host->offset = 0; + host->remain = host->cur_sg->length; + data->error = MMC_ERR_NONE; +} + +static inline int moxasd_next_sg(struct moxasd_host* host) +{ + /* + * Skip to next SG entry. + */ + host->cur_sg++; + host->num_sg--; + + /* + * Any entries left? + */ + if (host->num_sg > 0) { + host->offset = 0; + host->remain = host->cur_sg->length; + } + + return host->num_sg; +} + +static inline char *moxasd_kmap_sg(struct moxasd_host* host) +{ + host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) + + host->cur_sg->offset; + return host->mapped_sg; +} + +#if 0 // mask by Victor Yu. 03-19-2007, No used. +static inline void moxasd_check_data_crc(struct moxasd_host *host, struct mmc_data *data) +{ + unsigned int status; + + status = readl(&host->reg->status); + if ( status & MSD_DATA_CRC_OK ) { + writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear); + } + if ( status & MSD_DATA_CRC_FAIL ) { + writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear); + data->error = MMC_ERR_TIMEOUT; + } + if ( status & MSD_DATA_END ) { + writel(MSD_CLR_DATA_END, &host->reg->clear); + } +} + +static inline int moxasd_check_fifo_ready(struct moxasd_host *host) +{ + unsigned int status; + + status = readl(&host->reg->status); + if ( status & MSD_CARD_DETECT ) { // card is removed + return 0; + } + if ( status & (MSD_FIFO_URUN|MSD_FIFO_ORUN) ) { + writel(status&(MSD_FIFO_URUN|MSD_FIFO_ORUN), &host->reg->clear); + } + if ( status & MSD_DATA_TIMEOUT ) { + writel(MSD_CLR_DATA_TIMEOUT, &host->reg->clear); + return 0; + } + return 1; +} +#endif + +static void moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data) +{ + char *buffer; + int wcnt, i; + + if ( host->size == data->bytes_xfered ) { + return; + } + //buffer = moxasd_kmap_sg(host) + host->offset; + buffer = moxasd_kmap_sg(host); + if ( host->size > MSD_FIFO_LENB && host->dma ) { + apb_dma_conf_param param; + param.size = host->remain; + param.burst_mode = APB_DMAB_BURST_MODE; + param.data_width = APB_DMAB_DATA_WIDTH_4; + if ( data->flags & MMC_DATA_WRITE ) { + param.source_addr = (unsigned int)buffer; + param.dest_addr = (unsigned int)&host->reg->data_window; + param.dest_inc = APB_DMAB_DEST_INC_0; + param.source_inc = APB_DMAB_DEST_INC_4_16; + param.dest_sel = APB_DMAB_DEST_APB; + param.source_sel = APB_DMAB_SOURCE_AHB; + } else { + param.dest_addr = (unsigned int)buffer; + param.source_addr = (unsigned int)&host->reg->data_window; + param.source_inc = APB_DMAB_DEST_INC_0; + param.dest_inc = APB_DMAB_DEST_INC_4_16; + param.source_sel = APB_DMAB_DEST_APB; + param.dest_sel = APB_DMAB_SOURCE_AHB; + } + data->bytes_xfered += host->remain; +#if 0 // don't need to do this + host->offset = host->remain; + host->remain = 0; +#endif + apb_dma_conf(host->dma, ¶m); + kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + moxasd_next_sg(host); + apb_dma_enable(host->dma); + } else { +#if 0 + if ( host->remain >= MSD_FIFO_LENB ) + wcnt = MSD_FIFO_LENW; + else +#endif + wcnt = host->remain >> 2; + if ( data->flags & MMC_DATA_WRITE ) { + for ( i=0; ireg->data_window); + } else { + for ( i=0; ireg->data_window); + } + wcnt <<= 2; + host->offset += wcnt; + host->remain -= wcnt; + data->bytes_xfered += wcnt; + kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + /* because this will be just one time + if ( host->remain <= 0 ) + moxasd_next_sg(host); + */ + } +} + +static void moxasd_request_done(struct moxasd_host *host) +{ + struct mmc_request *mrq=host->mrq; + + if ( mrq == NULL ) { + return; + } + host->mrq = NULL; + host->data = NULL; + mmc_request_done(host->mmc, mrq); +} + +static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data) +{ + unsigned int timeout, datactrl; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + int blksz_bits; +#endif // LINUX_VERSION_CODE + + host->data = data; + moxasd_init_sg(host, data); + + // initialize the timeout value + timeout = (host->mmc->f_max/1000000) * (data->timeout_ns/1000); + timeout += data->timeout_clks; + writel(timeout, &host->reg->data_timer); + + // initialize the data size +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + host->size = data->blocks * data->blksz; + blksz_bits = ffs(data->blksz) - 1; + BUG_ON(1 << blksz_bits != data->blksz); +#else + host->size = data->blocks << data->blksz_bits; +#endif // LINUX_VERSION_CODE + writel(host->size, &host->reg->data_length); + + // initialize the data control +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + datactrl = (blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN; +#else + datactrl = (data->blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN; +#endif // LINUX_VERSION_CODE + if ( data->flags & MMC_DATA_WRITE ) { + datactrl |= MSD_DATA_WRITE; + } + if ( host->size > MSD_FIFO_LENB && host->dma ) { + datactrl |= MSD_DMA_EN; + } + writel(datactrl, &host->reg->data_control); + +#if 1 + //if ( host->size > MSD_FIFO_LENB && (data->flags & MMC_DATA_READ) ) { + if ( host->size > MSD_FIFO_LENB ) { + // disable the overrun & underrun interrupt + unsigned long flags; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + moxasd_do_fifo(host, data); + } else { + // enable the overrun & underrun interrupt + unsigned long flags; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE + writel(MSD_INT_FIFO_URUN|MSD_INT_FIFO_ORUN|MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + } +#endif +} + +static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd) +{ + unsigned int status, cmdctrl; + int retry=0; + +#if 1 // add by Victor Yu. 03-19-2007 + cmd->error = MMC_ERR_NONE; +#endif + + // first clear status + writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear); + + // write argument + writel(cmd->arg, &host->reg->argument); + + // write command + cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK; + if ( cmdctrl == SD_APP_SET_BUS_WIDTH || + cmdctrl == SD_APP_OP_COND || + cmdctrl == SD_APP_SEND_SCR ) // this is SD application specific command + cmdctrl |= MSD_APP_CMD; + if ( cmd->flags & MMC_RSP_LONG ) + cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP); + if ( cmd->flags & MMC_RSP_SHORT ) + cmdctrl |= MSD_NEED_RSP; + writel(cmdctrl|MSD_CMD_EN, &host->reg->command); + + // wait response + while ( retry++ < MSD_RETRY_COUNT ) { + status = readl(&host->reg->status); + if ( status & MSD_CARD_DETECT ) { // card is removed + cmd->error = MMC_ERR_TIMEOUT; +#if 0 // mask by Victor Yu. 03-19-2007 + return; +#else + break; +#endif + } + if ( cmdctrl & MSD_NEED_RSP ) { + if ( status & MSD_RSP_TIMEOUT ) { + writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear); + cmd->error = MMC_ERR_TIMEOUT; +#if 0 // mask by Victor Yu. 03-19-2007 + return; +#else + break; +#endif + } +#if 0 + if ( status & MSD_RSP_CRC_FAIL ) { +#else + if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) { +#endif + writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear); + cmd->error = MMC_ERR_BADCRC; +#if 0 // mask by Victor Yu. 03-19-2007 + return; +#else + break; +#endif + } + if ( status & MSD_RSP_CRC_OK ) { + writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear); + // read response + cmd->resp[0] = readl(&host->reg->response0); + cmd->resp[1] = readl(&host->reg->response1); + cmd->resp[2] = readl(&host->reg->response2); + cmd->resp[3] = readl(&host->reg->response3); +#if 0 // mask by Victor Yu. 03-19-2007 + cmd->error = MMC_ERR_NONE; + return; +#else + break; +#endif + } + } else { + if ( status & MSD_CMD_SENT ) { + writel(MSD_CLR_CMD_SENT, &host->reg->clear); +#if 0 // mask by Victor Yu. 03-19-2007 + cmd->error = MMC_ERR_NONE; + return; +#else + break; +#endif + } + } + } +#if 0 // mask by Victor Yu. 03-19-2007 + cmd->error = MMC_ERR_TIMEOUT; +#endif +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007 +static irqreturn_t moxasd_irq(int irq, void *devid) +#else +static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs) +#endif // LINUX_VERSION_CODE +{ + struct moxasd_host *host=devid; + unsigned int status; + + // get the interrupt status + + status = readl(&host->reg->status); + + // acknowledge the interurpt + if ( status & MSD_CARD_CHANGE ) { // has card inserted or removed + //writel(MSD_CLR_CARD_CHANGE, &host->reg->clear); + tasklet_schedule(&host->card_change_tasklet); + } + + if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) { +#if 0 // mask by Victor Yu. 03-19-2007 + writel(status&(MSD_FIFO_ORUN|MSD_FIFO_URUN), &host->reg->clear); +#endif + tasklet_schedule(&host->fifo_run_tasklet); + } + + return IRQ_HANDLED; +} + +static void moxasd_fifo_run(unsigned long param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + struct mmc_data *data; + + /* + if ( !moxasd_check_fifo_ready(host) && host->data ) { + host->size = host->data->bytes_xfered; + host->data->error = MMC_ERR_TIMEOUT; + if ( host->dma && host->size > MSD_FIFO_LENB ) { + apb_dma_disable(host->dma); + } + } + writel(readl(&host->reg->status)&(MSD_FIFO_URUN|MSD_FIFO_ORUN), &host->reg->clear); + */ + + spin_lock(&host->lock); +#if 1 // add by Victor Yu. 03-19-2007 + writel(readl(&host->reg->status)&(MSD_FIFO_URUN|MSD_FIFO_ORUN), &host->reg->clear); +#endif + if ( host->mrq == NULL ) { + spin_unlock(&host->lock); + return; + } +#if 1 // never happened + if ( host->data == NULL ) { + goto moxasd_fifo_run_done; + } +#endif + data = host->data; +#if 0 // add by Victor Yu. 03-19-2007 + if ( data == NULL ) { + spin_unlock(&host->lock); + return; + } +#endif + moxasd_do_fifo(host, data); + if ( host->size == data->bytes_xfered ) { +#if 0 + // maybe need to check the data is OK or fail + if ( data->error == MMC_ERR_NONE ) { + moxasd_check_data_crc(host, data); + } +#endif + if ( data->stop ) { + moxasd_send_command(host, data->stop); + } + } else { + spin_unlock(&host->lock); + //tasklet_schedule(&host->fifo_run_tasklet); + return; + } + +moxasd_fifo_run_done: + moxasd_request_done(host); + spin_unlock(&host->lock); +} + +static void moxasd_card_change(unsigned long param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + unsigned int status; + int delay; + + spin_lock(&host->lock); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007 + udelay(1000); + udelay(1000); + udelay(1000); +#else + udelay(3000); +#endif // LINUX_VERSION_CODE + status = readl(&host->reg->status); + if ( status & MSD_CARD_DETECT ) { // card removed + printk("Moxa CPU SD/MMC card is removed.\n"); + delay = 0; + if ( host->data ) { + if ( host->dma && host->size > MSD_FIFO_LENB ) + apb_dma_disable(host->dma); + host->size = host->data->bytes_xfered; + spin_unlock(&host->lock); + moxasd_fifo_run(*(unsigned long *)host); + spin_lock(&host->lock); + } + } else { // card inserted + printk("Moxa CPU SD/MMC card is inserted.\n"); +#if 0 // mask by Victor Yu. 03-16-2007 + if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // SD + host->mmc->f_max = 25000000; + host->mmc->mode = MMC_MODE_SD; + } else { + host->mmc->f_max = 20000000; + host->mmc->mode = MMC_MODE_MMC; + } +#endif + delay = 500; + } + writel(MSD_CLR_CARD_CHANGE, &host->reg->clear); + spin_unlock(&host->lock); + mmc_detect_change(host->mmc, msecs_to_jiffies(delay)); +} + +static void moxasd_dma_irq(void *param) +{ + struct moxasd_host *host=(struct moxasd_host *)param; + +#if 0 // mask by Victor Yu. 03-19-2007 + if ( host->data ) { + struct mmc_data *data=host->data; + if ( host->dma->error_flag ) { + host->size = data->bytes_xfered; + data->error = MMC_ERR_TIMEOUT; + } +#if 1 + tasklet_schedule(&host->fifo_run_tasklet); +#endif + } +#else + tasklet_schedule(&host->fifo_run_tasklet); +#endif +} + +static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct moxasd_host *host=mmc_priv(mmc); + struct mmc_command *cmd; + + spin_lock(&host->lock); + host->mrq = mrq; + cmd = mrq->cmd; + + // if no card inserted, return timeout error + if ( readl(&host->reg->status) & MSD_CARD_DETECT ) { // card is removed + cmd->error = MMC_ERR_TIMEOUT; + goto request_done; + } + + // request include data or not + if ( cmd->data ) { + moxasd_prepare_data(host, cmd->data); + } + + // do request command + moxasd_send_command(host, cmd); + + if ( cmd->data && cmd->error == MMC_ERR_NONE ) { + spin_unlock(&host->lock); + return; + } + +request_done: + moxasd_request_done(host); + spin_unlock(&host->lock); +} + +#define MIN_POWER (MMC_VDD_360 - MSD_SD_POWER_MASK) +static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct moxasd_host *host=mmc_priv(mmc); + + spin_lock(&host->lock); + if (ios->clock) { + int div; +#ifdef MSD_SUPPORT_GET_CLOCK + div = (host->sysclk / (host->mmc->f_max * 2)) - 1; +#else + div = (APB_CLK / (host->mmc->f_max * 2)) - 1; +#endif + if ( div > MSD_CLK_DIV_MASK ) + div = MSD_CLK_DIV_MASK; + else if ( div < 0 ) + div = 0; + if ( host->mmc->mode == MMC_MODE_SD ) + div |= MSD_CLK_SD; + writel(div, &host->reg->clock_control); + } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) { + /* + * Ensure that the clock is off. + */ + writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control); + } + + if ( ios->power_mode == MMC_POWER_OFF ) { + writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control); + } else { + unsigned short power; + if ( ios->vdd < MIN_POWER ) + power = 0; + else + power = ios->vdd - MIN_POWER; + writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control); + } + +#if 1 + if ( ios->bus_width == MMC_BUS_WIDTH_1 ) { + writel(MSD_SINGLE_BUS, &host->reg->bus_width); + } else { + writel(MSD_WIDE_BUS, &host->reg->bus_width); + } +#endif + spin_unlock(&host->lock); +} + +/* + * To check write protect or not. Return 0 for none, 1 for write protect. + */ +static int moxasd_get_ro(struct mmc_host *mmc) +{ + struct moxasd_host *host=mmc_priv(mmc); + + if ( readl(&host->reg->status) & MSD_WRITE_PROT ) + return 1; + else + return 0; +} + +static struct mmc_host_ops moxasd_ops = { + .request = moxasd_request, + .set_ios = moxasd_set_ios, + .get_ro = moxasd_get_ro, +}; + +static int moxasd_probe(struct device *dev) +{ + struct mmc_host *mmc; + struct moxasd_host *host=NULL; + int ret; + + mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + mmc->ops = &moxasd_ops; + mmc->f_min = 400000; + mmc->f_max = 25000000; + mmc->mode = MMC_MODE_SD; +#if 1 + mmc->ocr_avail = 0xffff00; // support 2.0v - 3.6v power +#else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->max_hw_segs = 128; + mmc->max_phys_segs = 128; + mmc->max_sectors = 128; + mmc->max_seg_size = mmc->max_sectors * 512; +#endif + + host = mmc_priv(mmc); + host->mmc = mmc; + spin_lock_init(&host->lock); + tasklet_init(&host->card_change_tasklet, moxasd_card_change, (unsigned long)host); + tasklet_init(&host->fifo_run_tasklet, moxasd_fifo_run, (unsigned long)host); + host->reg = (moxasd_reg *)CPE_SD_BASE; + host->dma = apb_dma_alloc(APB_DMA_SD_REQ_NO); + if ( host->dma ) { + apb_dma_set_irq(host->dma, moxasd_dma_irq, host); + } + +#ifdef MSD_SUPPORT_GET_CLOCK + // get system clock + { + unsigned int mul, val, div; + mul = (*(volatile unsigned int *)(CPE_PMU_BASE+0x30) >> 3) & 0x1ff; + val = (*(volatile unsigned int *)(CPE_PMU_BASE+0x0c) >> 4) & 0x7; + switch ( val ) { + case 0 : div = 2; break; + case 1 : div = 3; break; + case 2 : div = 4; break; + case 3 : div = 6; break; + case 4 : div = 8; break; + default : div = 2; break; + } + host->sysclk = (38684*mul + 10000) / (div * 10000); + host->sysclk = (host->sysclk * 1000000) / 2; + } +#endif + + // change I/O multiplexing to SD, so the GPIO 17-10 will be fail + *(volatile unsigned int *)(CPE_PMU_BASE+0x100) &= (~(0xff<<10)); + + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + writel(0, &host->reg->interrupt_mask); // disable all interrupt + writel(MSD_SDC_RST, &host->reg->command); // reset chip + while ( readl(&host->reg->command) & MSD_SDC_RST); // wait for reset finished + writel(0, &host->reg->interrupt_mask); // disable all interrupt + + // to check any card inserted or not +#if 0 + if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted + if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // is SD card + mmc->f_max = 25000000; + mmc->mode = MMC_MODE_SD; + } else { // is MMC card + mmc->f_max = 20000000; + mmc->mode = MMC_MODE_MMC; + } + } +#endif + + mmc->caps = MMC_CAP_4_BIT_DATA; + writel(MSD_WIDE_BUS, &host->reg->bus_width); + + cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE); + ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host); + if (ret) + goto out; + + //writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask); + writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask); + dev_set_drvdata(dev, mmc); + mmc_add_host(mmc); + + return 0; + + out: + if (mmc) + mmc_free_host(mmc); + + return ret; +} + +static int moxasd_remove(struct device *dev) +{ + struct mmc_host *mmc=dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (mmc) { + struct moxasd_host *host=mmc_priv(mmc); + + mmc_remove_host(mmc); + + // stop SD/MMC + if ( host->dma ) { + apb_dma_disable(host->dma); + apb_dma_release_irq(host->dma); + apb_dma_release(host->dma); + } + writel(0, &host->reg->interrupt_mask); + writel(0, &host->reg->power_control); + writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control); + + free_irq(IRQ_SD, host); + tasklet_kill(&host->card_change_tasklet); + tasklet_kill(&host->fifo_run_tasklet); + + mmc_free_host(mmc); + } + return 0; +} + +static struct platform_device moxasd_device = { + .name = "moxart-sd", + .id = -1, +}; + +static struct device_driver moxasd_driver = { + .name = "moxart-sd", + .bus = &platform_bus_type, + .probe = moxasd_probe, + .remove = moxasd_remove, +}; + +#if 1 // add by Victor Yu. 03-08-2007 +extern int moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c +#endif +static int __init moxasd_init(void) +{ + int ret; + + printk("Moxa CPU SD/MMC Device Driver V1.0 initialize "); +#if 1 // add by Victor Yu. 03-08-2007 + { + unsigned long flags; + local_irq_save(flags); + if ( moxa_gpio_sd_used_flag ) { + printk("The IO has used by other device driver !\n"); + local_irq_restore(flags); + return -ENODEV; + } + moxa_gpio_sd_used_flag = 1; + local_irq_restore(flags); + } +#endif + platform_device_register(&moxasd_device); + ret = driver_register(&moxasd_driver); + if ( ret ) { + printk("Modules load fail !\n"); + platform_device_unregister(&moxasd_device); + } else { + printk("Modules load OK.\n"); + } + return ret; +} + +static void __exit moxasd_exit(void) +{ + platform_device_unregister(&moxasd_device); + driver_unregister(&moxasd_driver); +} + +module_init(moxasd_init); +module_exit(moxasd_exit); + +MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/moxasd.h b/drivers/mmc/moxasd.h new file mode 100644 index 00000000..27eefb03 --- /dev/null +++ b/drivers/mmc/moxasd.h @@ -0,0 +1,108 @@ + +#ifndef _MOXASD_H +#define _MOXAAD_H + +// register +#define MSD_CMD_REG 0 +#define MSD_ARG_REG 4 +#define MSD_RESP0_REG 8 +#define MSD_RESP1_REG 0x0c +#define MSD_RESP2_REG 0x10 +#define MSD_RESP3_REG 0x14 +#define MSD_RESP_CMD_REG 0x18 +#define MSD_DATA_CTRL_REG 0x1c +#define MSD_DATA_TIMER_REG 0x20 +#define MSD_DATA_LEN_REG 0x24 +#define MSD_STATUS_REG 0x28 +#define MSD_CLEAR_REG 0x2c +#define MSD_INT_MASK_REG 0x30 +#define MSD_POWER_CTRL_REG 0x34 +#define MSD_CLOCK_CTRL_REG 0x38 +#define MSD_BUS_WIDTH_REG 0x3c +#define MSD_DATA_WIN_REG 0x40 +#define MSD_FEATURE_REG 0x44 +#define MSD_REVISION_REG 0x48 + +typedef struct _moxasd_reg { + unsigned int command; +#define MSD_SDC_RST (1<<10) +#define MSD_CMD_EN (1<<9) +#define MSD_APP_CMD (1<<8) +#define MSD_LONG_RSP (1<<7) +#define MSD_NEED_RSP (1<<6) +#define MSD_CMD_IDX_MASK 0x3f + unsigned int argument; + unsigned int response0; + unsigned int response1; + unsigned int response2; + unsigned int response3; + unsigned int response_command; +#define MSD_RSP_CMD_APP (1<<6) +#define MSD_RSP_CMD_IDX_MASK 0x3f + unsigned int data_control; +#define MSD_DATA_EN (1<<6) +#define MSD_DMA_EN (1<<5) +#define MSD_DATA_WRITE (1<<4) +#define MSD_BLK_SIZE_MASK 0x0f + unsigned int data_timer; + unsigned int data_length; +#define MSD_DATA_LEN_MASK 0xffffff + unsigned int status; +#define MSD_WRITE_PROT (1<<12) +#define MSD_CARD_DETECT (1<<11) +#define MSD_CARD_CHANGE (1<<10) +#define MSD_FIFO_ORUN (1<<9) +#define MSD_FIFO_URUN (1<<8) +#define MSD_DATA_END (1<<7) +#define MSD_CMD_SENT (1<<6) +#define MSD_DATA_CRC_OK (1<<5) +#define MSD_RSP_CRC_OK (1<<4) +#define MSD_DATA_TIMEOUT (1<<3) +#define MSD_RSP_TIMEOUT (1<<2) +#define MSD_DATA_CRC_FAIL (1<<1) +#define MSD_RSP_CRC_FAIL (1<<0) + unsigned int clear; +#define MSD_CLR_CARD_CHANGE (1<<10) +#define MSD_CLR_FIFO_ORUN (1<<9) +#define MSD_CLR_FIFO_URUN (1<<8) +#define MSD_CLR_DATA_END (1<<7) +#define MSD_CLR_CMD_SENT (1<<6) +#define MSD_CLR_DATA_CRC_OK (1<<5) +#define MSD_CLR_RSP_CRC_OK (1<<4) +#define MSD_CLR_DATA_TIMEOUT (1<<3) +#define MSD_CLR_RSP_TIMEOUT (1<<2) +#define MSD_CLR_DATA_CRC_FAIL (1<<1) +#define MSD_CLR_RSP_CRC_FAIL (1<<0) + unsigned int interrupt_mask; +#define MSD_INT_CARD_CHANGE (1<<10) +#define MSD_INT_FIFO_ORUN (1<<9) +#define MSD_INT_FIFO_URUN (1<<8) +#define MSD_INT_DATA_END (1<<7) +#define MSD_INT_CMD_SENT (1<<6) +#define MSD_INT_DATA_CRC_OK (1<<5) +#define MSD_INT_RSP_CRC_OK (1<<4) +#define MSD_INT_DATA_TIMEOUT (1<<3) +#define MSD_INT_RSP_TIMEOUT (1<<2) +#define MSD_INT_DATA_CRC_FAIL (1<<1) +#define MSD_INT_RSP_CRC_FAIL (1<<0) + unsigned int power_control; +#define MSD_SD_POWER_ON (1<<4) +#define MSD_SD_POWER_MASK 0x0f + unsigned int clock_control; +#define MSD_CLK_DIS (1<<8) +#define MSD_CLK_SD (1<<7) +#define MSD_CLK_DIV_MASK 0x7f + unsigned int bus_width; +#define MSD_WIDE_BUS_SUPPORT (1<<3) +#define MSD_WIDE_BUS (1<<2) // bus width=4 +#define MSD_SINGLE_BUS (1<<0) // bus width=1 + unsigned int data_window; + unsigned int feature; +#define MSD_CPRM_FUNCTION (1<<8) + unsigned int revision; +} moxasd_reg; + +#define MSD_FIFO_LENW 4 // 4 words, total 4 * 4 = 16 bytes +#define MSD_FIFO_LENB 16 // 16 bytes + +#endif // _MOXASD_H diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 72e6d73b..a3ffcd37 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -218,6 +218,15 @@ config MTD_RAM This option enables basic support for RAM chips accessed through a bus mapping driver. +config MTD_EPCS + tristate "Support for Altera EPCS Device" + depends on MTD + help + This option enables basic support for Alteras EPCS Device. Currently, + 1,4,16 and 64 MBit EPCS Devices are supported (EPCS1,EPCS4,EPCS16 and EPCS64). + Driver will automatically detect an EPCS chip if present and setup the size/sector size + accordingly. + config MTD_ROM tristate "Support for ROM chips in bus mapping" depends on MTD diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile index 75bc1c2a..1d1fdad4 100644 --- a/drivers/mtd/chips/Makefile +++ b/drivers/mtd/chips/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_RAM) += map_ram.o obj-$(CONFIG_MTD_ROM) += map_rom.o obj-$(CONFIG_MTD_SHARP) += sharp.o obj-$(CONFIG_MTD_ABSENT) += map_absent.o +obj-$(CONFIG_MTD_EPCS) += epcs.o epcs_low.o diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 296159ec..7b7c6845 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -608,6 +608,15 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, map->fldrv_priv = newcfi; *pcfi = newcfi; kfree(cfi); + } else { + struct flchip *chip; + int i; + for (i = 0; i < cfi->numchips; i++) { + chip = &cfi->chips[i]; + init_waitqueue_head(&chip->wq); + spin_lock_init(&chip->_spinlock); + chip->mutex = &chip->_spinlock; + } } return 0; @@ -1872,7 +1881,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip * If Instant Individual Block Locking supported then no need * to delay. */ - udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; + udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000 : 0; ret = WAIT_TIMEOUT(map, chip, adr, udelay); if (ret) { diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index 60e11a0a..a6ba62ce 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -387,6 +387,7 @@ static void print_cfi_ident(struct cfi_ident *cfip) break; case 4: + case 5: printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); break; diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index 2174c975..d821b71e 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c @@ -54,6 +54,21 @@ static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) return ret; } +static int mtd_generic_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf) +{ + struct map_info *map = (struct map_info *) mtd->priv; + *mtdbuf = (u_char *) (map->virt + ((int) from)); + *retlen = len; + return(0); +} + +static void mtd_generic_unpoint (struct mtd_info *mtd, u_char *addr, + loff_t from, size_t len) +{ + /* I don't know what we should do here */ +} + /* Hide all the horrid details, like some silly person taking get_module_symbol() away from us, from the caller. */ @@ -79,8 +94,13 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) */ module_put(drv->module); - if (ret) + if (ret) { + if (!ret->point) + ret->point = mtd_generic_point; + if (!ret->unpoint) + ret->unpoint = mtd_generic_unpoint; return ret; + } return NULL; } diff --git a/drivers/mtd/chips/epcs.c b/drivers/mtd/chips/epcs.c new file mode 100644 index 00000000..4490c5b2 --- /dev/null +++ b/drivers/mtd/chips/epcs.c @@ -0,0 +1,205 @@ +/* + * Altera EPCS Configuration device MTD Driver + * MTD Routines - read/write/erase etc... + * + * Jai Dhar, FPS-Tech + * + * Currently works with 1,4, 16 and 64 MBit EPCS Devices + * Module features: + * - Module detects the presence of an EPCS Device, between 1,4,16 and 64 Mbit EPCS chips + * - Automatically sets up EPCS Map physical size and erase block size + * - Important: The correct base address for the EPCS Avalon component must be specified + * in the Kernel configuration. This will not search for the component. The best way + * to find the base address is to look at the base address in SOPC Builder, and then + * in the SOPC Shell, use "nios2-flash-programmer --debug --epcs --base=" + * It will then tell you the base address which the registers were found. This + * isn't necessarily the same as . + * + * - Module tested with JFFS2 and ROMFS, both in RW and RO modes + * + * - TODO: Add transaction stats + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "epcs.h" + +static int epcs_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int epcs_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int epcs_erase(struct mtd_info *, struct erase_info *); +static void epcs_nop(struct mtd_info *); +static struct mtd_info *epcs_probe(struct map_info *map); + + +static struct mtd_chip_driver epcs_chipdrv = { + .probe = epcs_probe, + .name = "epcs", + .module = THIS_MODULE +}; + +static struct mtd_info *epcs_probe(struct map_info *map) +{ + struct mtd_info *mtd; + u_char x; + + printk(KERN_NOTICE "FPS-Tech EPCS MTD Driver (fps-tech.net)\n"); + + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) + return NULL; + + memset(mtd, 0, sizeof(*mtd)); + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "Resetting EPCS\n"); + #endif + + epcs_reset(); + + #if EPCS_DEBUG1 + printk(KERN_NOTICE "Using Avalon address: 0x%X\n",(u_int) map->phys); + #endif + + #if EPCS_DEBUG2 + epcs_print_regs(); + #endif + + + /* Check for EPCS Signature */ + switch (x=epcs_dev_find()) + { + case EPCS_SIG_1MBIT: + printk(KERN_NOTICE "1 Mbit EPCS Chip found\n"); + map->size = EPCS_SIZE_1MBIT; + mtd->erasesize = EPCS_SECSIZE_32KB; + break; + + case EPCS_SIG_4MBIT: + printk(KERN_NOTICE "4 Mbit EPCS Chip found\n"); + map->size = EPCS_SIZE_4MBIT; + mtd->erasesize = EPCS_SECSIZE_64KB; + break; + + case EPCS_SIG_16MBIT: + printk(KERN_NOTICE "16 Mbit EPCS Chip found\n"); + map->size = EPCS_SIZE_16MBIT; + mtd->erasesize = EPCS_SECSIZE_64KB; + break; + + case EPCS_SIG_64MBIT: + printk(KERN_NOTICE "64 Mbit EPCS Chip found\n"); + map->size = EPCS_SIZE_64MBIT; + mtd->erasesize = EPCS_SECSIZE_64KB; + break; + + default: + printk(KERN_NOTICE "No EPCS Chip found with ID: %d\n",x); + return NULL; + + } + + + map->fldrv = &epcs_chipdrv; + mtd->priv = map; + mtd->name = map->name; + mtd->type = MTD_NORFLASH; + mtd->size = map->size; + mtd->erase = epcs_erase; + mtd->read = epcs_read; + mtd->write = epcs_write; + mtd->sync = epcs_nop; + mtd->flags = MTD_CAP_NORFLASH; + + + #if EPCS_DEBUG1 + printk(KERN_NOTICE "Setting EPCS Page size to %d bytes\n",mtd->erasesize); + #endif + + __module_get(THIS_MODULE); + return mtd; +} + + +static int epcs_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) +{ + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_read, len: 0x%lx, from: 0x%lx\n",(u_long) len,(u_long) from); + #endif + + epcs_buf_read(buf,from,len); + *retlen = len; + return 0; +} + +static int epcs_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +{ + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_write, off: 0x%X, len: 0x%X\n",(u_int) to, (u_int) len); + #endif + + epcs_buf_write (buf, (u_int) to, (u_int) len); + + *retlen = len; + return 0; +} + +static int epcs_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_erase: off: 0x%X, len: 0x%X\n",(u_int) instr->addr, instr->len); + #endif + + epcs_buf_erase(instr->addr, instr->len, mtd->erasesize); + instr->state = MTD_ERASE_DONE; + + mtd_erase_callback(instr); + + return 0; +} + +static void epcs_nop(struct mtd_info *mtd) +{ + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_nop\n"); + #endif +} + + +int __init epcs_init(void) +{ + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_init registering driver\n"); + #endif + + register_mtd_chip_driver(&epcs_chipdrv); + return 0; +} + +void __exit epcs_exit(void) +{ + unregister_mtd_chip_driver(&epcs_chipdrv); + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_init un-registering driver\n"); + #endif +} + +module_init(epcs_init); +module_exit(epcs_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jai Dhar "); +MODULE_DESCRIPTION("MTD chip driver for EPCS Chips"); diff --git a/drivers/mtd/chips/epcs.h b/drivers/mtd/chips/epcs.h new file mode 100644 index 00000000..c18cb059 --- /dev/null +++ b/drivers/mtd/chips/epcs.h @@ -0,0 +1,79 @@ +/****************************************************************************** +* * +* * +******************************************************************************/ + +#ifndef __ALTERA_AVALON_SPI_REGS_H__ +#define __ALTERA_AVALON_SPI_REGS_H__ + +#define CONFIG_MTD_EPCS_DEBUG 0 +#define EPCS_DEBUG1 (CONFIG_MTD_EPCS_DEBUG >= 1) +#define EPCS_DEBUG2 (CONFIG_MTD_EPCS_DEBUG >= 2) +#define EPCS_DEBUG3 (CONFIG_MTD_EPCS_DEBUG >= 3) + + +#define EPCS_SIG_1MBIT 0x10 +#define EPCS_SIZE_1MBIT ((1 << 20)/8) + +#define EPCS_SIG_4MBIT 0x12 +#define EPCS_SIZE_4MBIT (EPCS_SIZE_1MBIT*4) + +#define EPCS_SIG_16MBIT 0x14 +#define EPCS_SIZE_16MBIT (EPCS_SIZE_4MBIT*4) + + +#define EPCS_SIG_64MBIT 0x16 +#define EPCS_SIZE_64MBIT (EPCS_SIZE_16MBIT*4) + +#define EPCS_SECSIZE_64KB ((1<<10)*64) +#define EPCS_SECSIZE_32KB ((1<<10)*32) + +#define EPCS_PAGESIZE 256 + +/*------------------------------------------------------------------------ + * SPI (http://www.altera.com/literature/ds/ds_nios_spi.pdf) + *----------------------------------------------------------------------*/ +typedef volatile struct nios_spi_t { + u_int rxdata; /* Rx data reg */ + u_int txdata; /* Tx data reg */ + u_int status; /* Status reg */ + u_int control; /* Control reg */ + u_int reserved; /* (master only) */ + u_int slaveselect; /* SPI slave select mask (master only) */ +}nios_spi_t; + +/* status register */ +#define NIOS_SPI_ROE (1 << 3) /* rx overrun */ +#define NIOS_SPI_TOE (1 << 4) /* tx overrun */ +#define NIOS_SPI_TMT (1 << 5) /* tx empty */ +#define NIOS_SPI_TRDY (1 << 6) /* tx ready */ +#define NIOS_SPI_RRDY (1 << 7) /* rx ready */ +#define NIOS_SPI_E (1 << 8) /* exception */ + +/* control register */ +#define NIOS_SPI_IROE (1 << 3) /* rx overrun int ena */ +#define NIOS_SPI_ITOE (1 << 4) /* tx overrun int ena */ +#define NIOS_SPI_ITRDY (1 << 6) /* tx ready int ena */ +#define NIOS_SPI_IRRDY (1 << 7) /* rx ready int ena */ +#define NIOS_SPI_IE (1 << 8) /* exception int ena */ +#define NIOS_SPI_SSO (1 << 10) /* override SS_n output */ + +typedef struct epcs_devinfo_t { + const char *name; /* Device name */ + u_char id; /* Device silicon id */ + u_char size; /* Total size log2(bytes)*/ + u_char num_sects; /* Number of sectors */ + u_char sz_sect; /* Sector size log2(bytes) */ + u_char sz_page; /* Page size log2(bytes) */ + u_char prot_mask; /* Protection mask */ +}epcs_devinfo_t; + + +u_char epcs_dev_find (void); +int epcs_reset (void); +int epcs_buf_read (u_char *dst, u_int off, u_int cnt); +int epcs_buf_write (const u_char *addr, u_int off, u_int cnt); +u_int epcs_buf_erase (u_int off, u_int len, u_int sz); +void epcs_print_regs(void); + +#endif /* __ALTERA_AVALON_SPI_REGS_H__ */ diff --git a/drivers/mtd/chips/epcs_low.c b/drivers/mtd/chips/epcs_low.c new file mode 100644 index 00000000..c529fd3c --- /dev/null +++ b/drivers/mtd/chips/epcs_low.c @@ -0,0 +1,486 @@ +/* + * (C) Copyright 2004, Psyent Corporation + * Scott McNutt + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + * + * + * Modified by Jai Dhar, FPS-Tech + * Modifications made to work with uClinux, linux 2.6.11 kernel + * + * TODO: - Add timeouts to while loops; kernel will stall if somethings + * goes bad otherwise + * - Possibly add verifying to writes? + * - LED Displays + * + */ + +#include +#include "epcs.h" + + + +/*-----------------------------------------------------------------------*/ +/* Operation codes for serial configuration devices + */ +#define EPCS_WRITE_ENA 0x06 /* Write enable */ +#define EPCS_WRITE_DIS 0x04 /* Write disable */ +#define EPCS_READ_STAT 0x05 /* Read status */ +#define EPCS_READ_BYTES 0x03 /* Read bytes */ +#define EPCS_READ_ID 0xab /* Read silicon id */ +#define EPCS_WRITE_STAT 0x01 /* Write status */ +#define EPCS_WRITE_BYTES 0x02 /* Write bytes */ +#define EPCS_ERASE_BULK 0xc7 /* Erase entire device */ +#define EPCS_ERASE_SECT 0xd8 /* Erase sector */ + +/* Device status register bits + */ +#define EPCS_STATUS_WIP (1<<0) /* Write in progress */ +#define EPCS_STATUS_WEL (1<<1) /* Write enable latch */ + + +static nios_spi_t *epcs; + +void epcs_print_regs(void) +{ + printk(KERN_NOTICE "Printing EPCS Registers\n"); + printk(KERN_NOTICE "rxdata: 0x%X, 0x%X\n",(u_int) &epcs->rxdata,(u_int) readl(&epcs->rxdata)); + printk(KERN_NOTICE "txdata: 0x%X, 0x%X\n",(u_int) &epcs->txdata,(u_int) readl(&epcs->txdata)); + printk(KERN_NOTICE "status: 0x%X, 0x%X\n",(u_int) &epcs->status,(u_int) readl(&epcs->status)); + printk(KERN_NOTICE "control: 0x%X, 0x%X\n",(u_int) &epcs->control,(u_int) readl(&epcs->control)); + printk(KERN_NOTICE "reserved: 0x%X, 0x%X\n",(u_int) &epcs->reserved,(u_int) readl(&epcs->reserved)); + printk(KERN_NOTICE "slaveselect: 0x%X, 0x%X\n",(u_int) &epcs->slaveselect,(u_int) readl(&epcs->slaveselect)); + +} + +/*********************************************************************** + * Device access + ***********************************************************************/ +static int epcs_cs (int assert) +{ + u_int tmp; + + if (assert) { + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_cs: Asserting CS\n"); + #endif + + writel (NIOS_SPI_SSO, &epcs->control); + } else { + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_cs: De-asserting CS\n"); + #endif + + /* Let all bits shift out */ + while ((readl (&epcs->status) & NIOS_SPI_TMT) == 0); + + tmp = readl (&epcs->control); + writel (0,&epcs->control); + } + + return 0; + + + +} + +static int epcs_tx (unsigned char c) +{ + u_int status; + + status = (u_int)readl(&epcs->status); + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_tx: 0x%X, 0x%X, 0x%X\n",(u_int) &epcs->status,status,NIOS_SPI_TRDY); + #endif + + //start = get_timer (0); + while ((status & NIOS_SPI_TRDY) == 0) + { + status = (u_int)readl(&epcs->status); + } + + /*if (get_timer (start) > EPCS_TIMEOUT) + return (-1);*/ + writel (c, &epcs->txdata); + return (0); +} + +static int epcs_rx (void) +{ + u_int status; + + status = (u_int)readl(&epcs->status); + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_rx: 0x%X, 0x%X, 0x%X\n",(u_int) &epcs->status,status,NIOS_SPI_RRDY); + #endif + + while ((status & NIOS_SPI_RRDY) == 0) + { + status = (u_int)readl(&epcs->status); + } + return (readl (&epcs->rxdata)); +} + +#if 0 +static unsigned char bitrev[] = { + 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f +}; +#endif + +#if 0 +static unsigned char epcs_bitrev (unsigned char c) +{ + unsigned char val; + + val = bitrev[c>>4]; + val |= bitrev[c & 0x0f]<<4; + return (val); +} +#endif +static void epcs_rcv (unsigned char *dst, int len) +{ + while (len--) { + epcs_tx (0); + *dst++ = epcs_rx (); + } +} + +#if 0 +static void epcs_rrcv (unsigned char *dst, int len) +{ + while (len--) { + epcs_tx (0); + *dst++ = epcs_bitrev (epcs_rx ()); + } +} +#endif + +static void epcs_snd (const unsigned char *src, int len) +{ + while (len--) { + epcs_tx (*src++); + epcs_rx (); + } +} + +#if 0 +static void epcs_rsnd (unsigned char *src, int len) +{ + while (len--) { + epcs_tx (epcs_bitrev (*src++)); + epcs_rx (); + } +} + +#endif + +static void epcs_wr_enable (void) +{ + epcs_cs (1); + epcs_tx (EPCS_WRITE_ENA); + epcs_rx (); + epcs_cs (0); +} + +static unsigned char epcs_status_rd (void) +{ + unsigned char status; + + epcs_cs (1); + epcs_tx (EPCS_READ_STAT); + epcs_rx (); + epcs_tx (0); + status = epcs_rx (); + epcs_cs (0); + return (status); +} + +#if 0 +static void epcs_status_wr (unsigned char status) +{ + epcs_wr_enable (); + epcs_cs (1); + epcs_tx (EPCS_WRITE_STAT); + epcs_rx (); + epcs_tx (status); + epcs_rx (); + epcs_cs (0); + return; +} +#endif + +/*********************************************************************** + * Device information + ***********************************************************************/ + +int epcs_reset (void) +{ + /* When booting from an epcs controller, the epcs bootrom + * code may leave the slave select in an asserted state. + * This causes two problems: (1) The initial epcs access + * will fail -- not a big deal, and (2) a software reset + * will cause the bootrom code to hang since it does not + * ensure the select is negated prior to first access -- a + * big deal. Here we just negate chip select and everything + * gets better :-) + */ + + /* Assign base address */ + epcs = (nios_spi_t *) ((na_epcs_controller | 0x200) | 0x80000000); + /* Clear status and control registers */ + +#if 1 + writel(0,&epcs->status); + writel(0,&epcs->control); + writel(1,&epcs->slaveselect); +#endif + + epcs_cs (0); /* Negate chip select */ + + + return (0); +} + +u_char epcs_dev_find (void) +{ + unsigned char buf[4]; + unsigned char id; + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_dev_find()\n"); + #endif + + /* Read silicon id requires 3 "dummy bytes" before it's put + * on the wire. + */ + buf[0] = EPCS_READ_ID; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + epcs_cs (1); + + epcs_snd (buf,4); + epcs_rcv (buf,1); + if (epcs_cs (0) == -1) + return (0); + id = buf[0]; + + + #if EPCS_DEBUG1 + printk(KERN_NOTICE "epcs_dev_find: Device ID: 0x%X\n",id); + #endif + + return id; + +#if 0 + + /* Find the info struct */ + i = 0; + while (devinfo[i].name) { + if (id == devinfo[i].id) { + dev = &devinfo[i]; + break; + } + i++; + } + + return (dev); +#endif +} + +/*********************************************************************** + * Misc Utilities + ***********************************************************************/ + +#if 1 +u_int epcs_buf_erase (u_int off, u_int len, u_int sz) +{ + u_char buf[4]; + + /* Erase the requested sectors. An address is required + * that lies within the requested sector -- we'll just + * use the first address in the sector. + */ + + #if EPCS_DEBUG2 + /* Check if address is a sector */ + printk(KERN_NOTICE "epcs_erase(): off: 0x%X, len: 0x%X, sz: 0x%X\n",off,len,sz); + #endif + + if ((off % sz) || (len % sz)) + { + printk(KERN_NOTICE "epcs_erase: Address is not sector-aligned, halting!\n"); + while(1); + } + + while (len) { + + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_erase: Erasing 0x%X\n",off); + #endif + + buf[0] = EPCS_ERASE_SECT; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + epcs_wr_enable (); + epcs_cs (1); + epcs_snd (buf,4); + epcs_cs (0); + + /* Wait for erase to complete */ + while (epcs_status_rd() & EPCS_STATUS_WIP); + + len -= sz; + off += sz; + } + return (0); +} +#endif + +#if 1 +int epcs_buf_read (u_char *dst, u_int off, u_int cnt) +{ + u_char buf[4]; + + + buf[0] = EPCS_READ_BYTES; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + epcs_cs (1); + epcs_snd (buf,4); + //epcs_rrcv ((u_char *)addr, cnt); + epcs_rcv (dst, cnt); + epcs_cs (0); + + return (0); +} + +#endif + +#if 1 +int epcs_buf_write (const u_char *addr, u_int off, u_int cnt) +{ + u_int wrcnt; + u_int pgsz; + u_char buf[4]; + + pgsz = EPCS_PAGESIZE; + + #if EPCS_DEBUG2 + printk(KERN_NOTICE "epcs_buf_write(): 0x%X, 0x%X\n",cnt,off); + #endif + + while (cnt) { + if (off % pgsz) + wrcnt = pgsz - (off % pgsz); + else + wrcnt = pgsz; + wrcnt = (wrcnt > cnt) ? cnt : wrcnt; + + buf[0] = EPCS_WRITE_BYTES; + buf[1] = off >> 16; + buf[2] = off >> 8; + buf[3] = off; + + #if EPCS_DEBUG3 + printk(KERN_NOTICE "epcs_buf_write: wrcnt: 0x%X, offset: 0x%X\n",wrcnt,off); + #endif + + epcs_wr_enable (); + epcs_cs (1); + epcs_snd (buf,4); + //epcs_rsnd ((unsigned char *)addr, wrcnt); + epcs_snd (addr, wrcnt); + epcs_cs (0); + + /* Wait for write to complete */ + while (epcs_status_rd() & EPCS_STATUS_WIP); + + cnt -= wrcnt; + off += wrcnt; + addr += wrcnt; + } + + return (0); +} + +#endif + +#if 0 +int epcs_verify (ulong addr, ulong off, ulong cnt, ulong *err) +{ + ulong rdcnt; + unsigned char buf[256]; + unsigned char *start,*end; + int i; + + start = end = (unsigned char *)addr; + while (cnt) { + rdcnt = (cnt>sizeof(buf)) ? sizeof(buf) : cnt; + epcs_read ((ulong)buf, off, rdcnt); + for (i=0; isz_sect); + off = sectsz * sect; + end = off + sectsz; + + while (off < end) { + epcs_read ((ulong)buf, off, sizeof(buf)); + for (i=0; i < sizeof(buf); i++) { + if (buf[i] != 0xff) { + *offset = off + i; + return (0); + } + } + off += sizeof(buf); + } + return (1); +} + +#endif diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 1154dac7..1c653bbe 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -52,13 +53,18 @@ #define AM29LV800BT 0x22DA #define AM29LV160DT 0x22C4 #define AM29LV160DB 0x2249 +#define AM29BDD160GB 0x7E08 #define AM29F017D 0x003D #define AM29F016D 0x00AD #define AM29F080 0x00D5 #define AM29F040 0x00A4 #define AM29LV040B 0x004F #define AM29F032B 0x0041 +#define AM29LV065D 0x0093 +#define AM29DL323GB 0x2253 #define AM29F002T 0x00B0 +#define AM29LV004T 0x00B5 +#define AM29LV004B 0x00B6 /* Atmel */ #define AT49BV512 0x0003 @@ -276,6 +282,66 @@ struct amd_flash_info { static const struct amd_flash_info jedec_table[] = { { .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV004T, + .name = "AMD AM29LV004T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV004B, + .name = "AMD AM29LV004B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV065D, + .name = "AMD AM29LV065D", + .uaddr = { + [0] = MTD_UADDR_DONT_CARE /* x8 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,128) + } + },{ + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29DL323GB, + .name = "AMD AM29DL323GB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0AAA_0x0555 /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x2000,8), + ERASEINFO(0x10000,63) + } + },{ + .mfr_id = MANUFACTURER_AMD, .dev_id = AM29F032B, .name = "AMD AM29F032B", .uaddr = { @@ -323,6 +389,21 @@ static const struct amd_flash_info jedec_table[] = { } }, { .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29BDD160GB, + .name = "AMD AM29BDD160GB", + .uaddr = { + [0] = MTD_UADDR_0x1554_0x0AAA /* x32 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 3, + .regions = { + ERASEINFO(0x01000,8), + ERASEINFO(0x10000,32), + ERASEINFO(0x01000,8) + } + }, { + .mfr_id = MANUFACTURER_AMD, .dev_id = AM29LV400BB, .name = "AMD AM29LV400BB", .uaddr = { diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 78872c3f..58396ac4 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -86,7 +86,12 @@ static unsigned long __initdata doc_locations[] = { 0xff000000, #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) 0xff000000, -##else +#elif defined(CONFIG_SH_SECUREEDGE5410) + 0x00000000, + 0x04000000, +#elif defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_SE5100) + 0x50000000, +#else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 24747bdc..080ebb60 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -211,6 +211,25 @@ config MTD_NETtel help Support for flash chips on NETtel/SecureEdge/SnapGear boards. +# FIXME +config MTD_UC7110 + tristate "CFI Flash device mapped on Moxa UC7110-LX board" + depends on MTD_CFI && MTD_PARTITIONS + help + Support for flash chips on the Moxa UC7110-LX version2 platform. + +config MTD_SNAPGEODE + tristate "CFI flash device on SnapGear/GEODE boards" + depends on X86 && MTD_PARTITIONS + help + Support for flash chips on SnapGear GEODE based boards. + +config MTD_SNAPARM + tristate 'CFI Flash device mapped on SnapGear/Cyberguard ARM/XSCALE boards' + depends on MTD_CFI && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS + help + Support for flash chips on the SnapGear/Cyberguard ARM/XSCALE platforms. + config MTD_ALCHEMY tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support" depends on SOC_AU1X00 @@ -565,6 +584,79 @@ config MTD_UCLINUX help Map driver to support image based filesystems for uClinux. +config MTD_UCLINUX_EBSS + bool "uClinux RAM/ROM filesystem is located at ebss" + depends on MTD_UCLINUX + default y + help + The filesystem is located directly after the kernel in memory. + +config MTD_UCLINUX_ADDRESS + hex "uClinux RAM/ROM filesystem address" + default 0x1400000 + depends on MTD_UCLINUX && !MTD_UCLINUX_EBSS + help + The filesystem is located at the given address. + +choice + prompt "uClinux RAM/ROM is located in ROM/RAM" + default MTD_UCLINUX_RAM + depends on MTD_UCLINUX && !MTD_UCLINUX_EBSS + +config MTD_UCLINUX_RAM + bool "RAM" +config MTD_UCLINUX_ROM + bool "ROM" +endchoice + +config MTD_COBRA5329 + tristate "Cobra5329 mapping" + depends on MTD_PARTITIONS && COBRA5329 + help + Map driver to support Cobra5329 Flash. + +config MTD_SNAPGEARuC + tristate "SnapGear uClinux RAM/ROM filesystem support" + depends on MTD_PARTITIONS + help + Map driver for Flash and RAM in the SnapGear devices. + +config MTD_M520x + tristate "Freescale M520xEVB Flash filesystem support" + depends on MTD_PARTITIONS + help + Map for M5208EVB & M5207EVB Flash Partition. + +config MTD_CPU16B + tristate "RAM/ROM filesystem support for Sarasvati from Sneha Technologies S.L." + depends on MTD_PARTITIONS && SNEHA && CPU16B + help + Map driver to support image based filesystems for CPU16B. + +choice + prompt "Flash Size" + depends on MTD_SNAPGEARuC + default AUTO + +config FLASHAUTO + bool "AUTO" +config FLASH128KB + bool "128KB" +config FLASH1MB + bool "1MB" +config FLASH2MB + bool "2MB" +config FLASH4MB + bool "4MB" +config FLASH6MB + bool "6MB" +config FLASH8MB + bool "8MB" +config FLASH16MB + bool "16MB" + +endchoice + config MTD_WRSBC8260 tristate "Map driver for WindRiver PowerQUICC II MPC82xx board" depends on (SBC82xx || SBC8560) @@ -606,12 +698,34 @@ config MTD_BAST_MAXSIZE depends on MTD_BAST default "4" +config MTD_DM270 + tristate "CFI Flash device mapped on TI TMS320DM270" + depends on ARM && MACH_DM270 && MTD_CFI + help + This enables access to the flash chips on TI TMS320DM270 based + boards. + config MTD_SHARP_SL bool "ROM maped on Sharp SL Series" depends on MTD && ARCH_PXA help This enables access to the flash chip on the Sharp SL Series of PDAs. +config MTD_COBRA5272 + tristate "Flash device mapped on COBRA5272" + depends on MTD && COBRA5272 + help + This enables access to the flash chips (2MB) on the COBRA5272. + If you have such board, say 'Y'. + +config MTD_COBRA5282 + tristate "Flash device mapped on COBRA5282" + depends on MTD && COBRA5282 + help + This enables access to the flash chips (4MB) on the COBRA5282. + If you have such board, say 'Y'. + + config MTD_PLATRAM tristate "Map driver for platform device RAM (mtd-ram)" depends on MTD @@ -622,5 +736,40 @@ config MTD_PLATRAM This selection automatically selects the map_ram driver. +config MTD_AVNET5282 + tristate "CFI Flash device mapped on AVNET5282" + depends on MTD_PARTITIONS && !MMU + help + Support for flash chip on Avnet5282 board + +config MTD_MICROTRONIX + tristate "Maps for Microtronix boards, or Altera Cyclone 1C12 Eval board" + depends on MTD_PARTITIONS && !MMU && ( MICROTRONIX_UKIT || MICROTRONIX_STRATIX || MICROTRONIX_CYCLONE || ALTERA_CYCLONE_1C12_EVAL || MICROTRONIX_PSK) + default n + help + Map driver for accessing flash memory on Microtronix Development + board (including Stratix, Cyclone and ukit), or Altera Cyclone 1C12 + Evaluation board. + +config MTD_EPCS_MAP + tristate "Maps for Altera EPCS Configuration Device" + depends on MTD_PARTITIONS && !MMU && MTD_EPCS + default y + help + Map driver for accessing EPCS Flash by Altera. Please edit epcs_map.c + to setup the appropriate partitions. Since the driver will automatically + detect the EPCS chip present, it is your responsibility to setup + appropriate partition sizes/offsets such that you do not conflict with + the detected size. IE: Don't specify a partition size of 4 Megabytes when + you only have a 1 Megabit chip available! + +config MTD_ALTERA + tristate "Maps for Altera Nios Development Kit" + depends on MTD_PARTITIONS && !MMU && ( ALTERA_STRATIX || ALTERA_STRATIX_PRO || ALTERA_CYCLONE || ALTERA_STRATIX_II) + default y + help + Map driver for accessing flash memory on Altera Nios Development kit, + Cyclone, Stratix or Stratix Pro edition. + endmenu diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 191c1928..7499cca3 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -40,7 +40,10 @@ obj-$(CONFIG_MTD_VMAX) += vmax301.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o +obj-$(CONFIG_MTD_UCLINUX) += uclinux.o +obj-$(CONFIG_MTD_SNAPGEARuC) += snapgear-uc.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_M520x) += m520x.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o obj-$(CONFIG_MTD_LASAT) += lasat.o @@ -51,6 +54,8 @@ obj-$(CONFIG_MTD_FORTUNET) += fortunet.o obj-$(CONFIG_MTD_REDWOOD) += redwood.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o +obj-$(CONFIG_MTD_SNAPGEODE) += snapgeode.o +obj-$(CONFIG_MTD_SNAPARM) += snaparm.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o obj-$(CONFIG_MTD_EBONY) += ebony.o obj-$(CONFIG_MTD_OCOTEA) += ocotea.o @@ -58,6 +63,9 @@ obj-$(CONFIG_MTD_BEECH) += beech-mtd.o obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o obj-$(CONFIG_MTD_WALNUT) += walnut.o obj-$(CONFIG_MTD_H720X) += h720x-flash.o +obj-$(CONFIG_MTD_MICROTRONIX) += microtronix.o +obj-$(CONFIG_MTD_ALTERA) += altera.o +obj-$(CONFIG_MTD_EPCS_MAP) += epcs_map.o obj-$(CONFIG_MTD_SBC8240) += sbc8240.o obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o obj-$(CONFIG_MTD_MPC1211) += mpc1211.o @@ -65,8 +73,15 @@ obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o +obj-$(CONFIG_MTD_CPU16B) += mtdcpu16b.o +obj-$(CONFIG_MTD_DM270) += dm270-flash.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o +obj-$(CONFIG_MTD_COBRA5272) += cobra5272.o +obj-$(CONFIG_MTD_COBRA5282) += cobra5282.o +obj-$(CONFIG_MTD_COBRA5329) += cobra5329.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o obj-$(CONFIG_MTD_TQM834x) += tqm834x.o +obj-$(CONFIG_MTD_AVNET5282) += avnet5282.o +obj-$(CONFIG_MTD_UC7110) += uc7110.o diff --git a/drivers/mtd/maps/altera.c b/drivers/mtd/maps/altera.c new file mode 100644 index 00000000..4f0be50c --- /dev/null +++ b/drivers/mtd/maps/altera.c @@ -0,0 +1,178 @@ +/* + * Normal mappings of altera Nios II development kit flash in physical memory + * Derived from physmap.c, by Microtronix Datacom Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* map solutions */ +#define WINDOW_ADDR na_flash_kernel +#define WINDOW_SIZE na_flash_kernel_size +#define BUSWIDTH 1 + +static struct mtd_info *mymtd; + + +struct map_info ndk_amd_map = { + .name = "Altera NDK flash (AMD)", + .size = WINDOW_SIZE, + .bankwidth = BUSWIDTH, + .phys = WINDOW_ADDR, +}; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition *mtd_parts; +static int mtd_parts_nb; + +static struct mtd_partition alteramap_partitions[] = { +#ifdef CONFIG_ALTERA_STRATIX_II + { + .name = "romfs/jffs2", + .size = 0x600000, + .offset = 0x200000, + },{ + .name = "loader/kernel", + .size = 0x200000, + .offset = 0, + }, { + .name = "User configuration", + .size = 0x400000, + .offset = 0x800000, + }, { + .name = "safe configuration", + .size = 0x400000, + .offset = 0xc00000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +#elif defined(CONFIG_ALTERA_STRATIX_PRO) + { + .name = "romfs/jffs2", + .size = 0x200000, + .offset = 0x200000, + },{ + .name = "loader/kernel", + .size = 0x200000, + .offset = 0, + }, { + .name = "User configuration", + .size = 0x200000, + .offset = 0x400000, + }, { + .name = "safe configuration", + .size = 0x200000, + .offset = 0x600000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +#else + { + .name = "romfs/jffs2", + .size = 0x400000, + .offset = 0x200000, + },{ + .name = "loader/kernel", + .size = 0x200000, + .offset = 0, + }, { + .name = "User configuration", + .size = 0x100000, + .offset = 0x600000, + }, { + .name = "safe configuration", + .size = 0x100000, + .offset = 0x700000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +#endif +}; + +#define NUM_PARTITIONS (sizeof(alteramap_partitions)/sizeof(struct mtd_partition)) +const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL}; + +#endif /* CONFIG_MTD_PARTITIONS */ + +int __init init_alteramap(void) +{ + static const char *rom_probe_types[] = {"cfi_probe", "jedec_probe", 0 }; + const char **type; + + ndk_amd_map.virt = (unsigned long *)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); +/* + if (!ndk_amd_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } +*/ + simple_map_init(&ndk_amd_map); + + mymtd = 0; + type = rom_probe_types; + for(; !mymtd && *type; type++) { + mymtd = do_map_probe(*type, &ndk_amd_map); + } + if (mymtd) { + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + &mtd_parts, 0); + + if (mtd_parts_nb > 0) + { + add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + return 0; + } + + if (NUM_PARTITIONS != 0) + { + printk(KERN_NOTICE + "Using Altera NDK partition definition\n"); + add_mtd_partitions (mymtd, alteramap_partitions, NUM_PARTITIONS); + return 0; + } + +#endif + add_mtd_device(mymtd); + + return 0; + } + + iounmap((void *)ndk_amd_map.virt); + return -ENXIO; +} + +static void __exit cleanup_alteramap(void) +{ +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_parts_nb) { + del_mtd_partitions(mymtd); + kfree(mtd_parts); + } else if (NUM_PARTITIONS) { + del_mtd_partitions(mymtd); + } else { + del_mtd_device(mymtd); + } +#else + del_mtd_device(mymtd); +#endif + map_destroy(mymtd); + + iounmap((void *)ndk_amd_map.virt); + ndk_amd_map.virt = 0; +} + +module_init(init_alteramap); +module_exit(cleanup_alteramap); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Microtronix Datacom "); +MODULE_DESCRIPTION("MTD map driver for Altera Nios Development Kit"); diff --git a/drivers/mtd/maps/avnet5282.c b/drivers/mtd/maps/avnet5282.c new file mode 100644 index 00000000..bd077ca7 --- /dev/null +++ b/drivers/mtd/maps/avnet5282.c @@ -0,0 +1,108 @@ +/* + * + * Normal mappings of chips in physical memory + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define WINDOW_ADDR 0xff800000 // Flash Start addr. +#define WINDOW_SIZE 0x00800000 // Flash Size: 8 MB +#define BUSWIDTH 2 + +#define NUM_PARTITIONS (sizeof(avnet5282_partitions) / sizeof (avnet5282_partitions[0])) + +/*************************************************************************************/ + +static struct mtd_partition avnet5282_partitions[] = { + { + .name = "uboot (256 KB)", + .size = 0x40000, + .offset = 0x0, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "kernel (3 MB)", + .size = 0x300000, + .offset = 0x40000 + }, + { + .name = "rootfs (4,75 MB)", + .size = 0x4C0000, + .offset = 0x340000 + } +}; + +/*************************************************************************************/ + +struct map_info avnet5282_map = { + .name = "MCF5282 flash", + .size = WINDOW_SIZE, + .phys = WINDOW_ADDR, + .bankwidth = BUSWIDTH +}; + +static struct mtd_info *mymtd; + +/*************************************************************************************/ + +static int __init init_avnet5282(void) +{ + avnet5282_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); + + if (avnet5282_map.virt == 0) { + printk(KERN_NOTICE "Failed to ioremap FLASH memory area.\n"); + return -EIO; + } + simple_map_init(&avnet5282_map); + + mymtd = do_map_probe("cfi_probe", &avnet5282_map); + + if(!mymtd){ + printk(KERN_NOTICE "Flash 5282 error, can't map"); + iounmap((void *)avnet5282_map.virt); + return -ENXIO; + } + printk(KERN_NOTICE "MCF5282 flash device: %dMiB at 0x%08x\n", mymtd->size >> 20, WINDOW_ADDR); + + mymtd->owner = THIS_MODULE; + mymtd->erasesize = 0x40000; + + add_mtd_partitions(mymtd, avnet5282_partitions, NUM_PARTITIONS); + return 0; +} + +/*************************************************************************************/ + +static void __exit cleanup_avnet5282(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (avnet5282_map.virt) { + iounmap((void *)avnet5282_map.virt); + avnet5282_map.virt = 0; + } + return; +} + +/*************************************************************************************/ + +module_init(init_avnet5282); +module_exit(cleanup_avnet5282); + +MODULE_AUTHOR("Daniel Alomar i Claramonte"); +MODULE_DESCRIPTION("Mapejat Xip Flash 28F640JA"); +MODULE_LICENSE("GPL"); + +/*************************************************************************************/ diff --git a/drivers/mtd/maps/cobra5272.c b/drivers/mtd/maps/cobra5272.c new file mode 100644 index 00000000..3b3049c9 --- /dev/null +++ b/drivers/mtd/maps/cobra5272.c @@ -0,0 +1,153 @@ +/* + * Copyright Boris Koprinarov + * + * cobra5272.c ,v 1.14 2005/08/31 13:24:14 + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLASH_PHYS_ADDR 0xffe00000 +#define FLASH_SIZE 0x200000 + +#define FLASH_PARTITION0_ADDR 0x1000000 +#define FLASH_PARTITION0_SIZE 0x1000000 + +struct map_info flagadm_map = { + .name = "Flash chip on COBRA5272", + .size = FLASH_SIZE, + .bankwidth = 2, +}; + +struct mtd_partition flagadm_parts[] = { + { + .name = "boot (16K)", + .offset = 0x0, + .size = 0x4000 + + }, + { + .name = "kernel (512K)", + .offset = 0x80000, + .size = 0x80000 + }, + { + .name = "rootfs (1024K)", + .offset = 0x100000, + .size = 0x100000 + }, + { + .name = "spare (8K)", + .offset = 0x4000, + .size = 0x2000 + }, + { + .name = "spare (8K)", + .offset = 0x6000, + .size = 0x2000 + }, + { + .name = "spare (256K)", + .offset = 0x40000, + .size = 0x40000 + }, + { + .name = "complete (2048K)", + .offset = 0x0, + .size = 0x200000 + }, + { + .name = "boot J13 (256K)", + .offset = 0x100000, + .size = 0x40000 + }, + { + .name = "kernel J13 (512K)", + .offset = 0x140000, + .size = 0x80000 + }, + { + .name = "rootfs J13 (256K)", + .offset = 0x1c0000, + .size = 0x40000 + } + +}; + +#define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition)) + +static struct mtd_info *mymtd; + +int __init init_flagadm(void) +{ + printk(KERN_NOTICE "COBRA5272 flash device: %x at %x\n", + FLASH_SIZE, FLASH_PHYS_ADDR); + + flagadm_map.phys = FLASH_PHYS_ADDR; + flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, + FLASH_SIZE); + + if (!flagadm_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + + simple_map_init(&flagadm_map); + + mymtd = do_map_probe("cfi_probe", &flagadm_map); + if (mymtd) { + mymtd->owner = THIS_MODULE; + add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT); + printk(KERN_NOTICE "COBRA5272 flash device initialized\n"); + return 0; + } + + iounmap((void *)flagadm_map.virt); + return -ENXIO; +} + +static void __exit cleanup_flagadm(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (flagadm_map.virt) { + iounmap((void *)flagadm_map.virt); + flagadm_map.virt = 0; + } +} + +module_init(init_flagadm); +module_exit(cleanup_flagadm); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Boris Koprinarov "); +MODULE_DESCRIPTION("MTD map driver for COBRA5272 board"); diff --git a/drivers/mtd/maps/cobra5282.c b/drivers/mtd/maps/cobra5282.c new file mode 100644 index 00000000..fee9d532 --- /dev/null +++ b/drivers/mtd/maps/cobra5282.c @@ -0,0 +1,138 @@ +/* + * Copyright Boris Koprinarov + * + * cobra5282.c, v 1.14 2005/08/31 13:24:14 + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLASH_PHYS_ADDR 0xffc00000 +#define FLASH_SIZE 0x400000 + +#define FLASH_PARTITION0_ADDR 0xFFC00000 +#define FLASH_PARTITION0_SIZE 0x400000 + +struct map_info flagadm_map = { + .name = "Flash chip on COBRA5282", + .size = FLASH_SIZE, + .bankwidth = 2, +}; + +struct mtd_partition flagadm_parts[] = { + { + .name = "boot (256K)", + .offset = 0x0, + .size = 0x40000 + + }, + { + .name = "kernel (1408K)", + .offset = 0x40000, + .size = 0x160000 + }, + { + .name = "rootfs (2048K)", + .offset = 0x1A0000, + .size = 0x200000 + }, + { + .name = "spare (32K)", + .offset = 0x0, + .size = 0x8000 + }, + { + .name = "user 1 (384K)", + .offset = 0x3A0000, + .size = 0x60000 + }, + { + .name = "user 2 (2432K)", + .offset = 0x1A0000, + .size = 0x260000 + }, + { + .name = "complete (4096K)", + .offset = 0x0, + .size = 0x400000 + } + +}; + +#define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition)) + +static struct mtd_info *mymtd; + +int __init init_flagadm(void) +{ + printk(KERN_NOTICE "COBRA5282 flash device: %x at %x\n", + FLASH_SIZE, FLASH_PHYS_ADDR); + + flagadm_map.phys = FLASH_PHYS_ADDR; + flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, + FLASH_SIZE); + + if (!flagadm_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + + simple_map_init(&flagadm_map); + + mymtd = do_map_probe("cfi_probe", &flagadm_map); + if (mymtd) { + mymtd->owner = THIS_MODULE; + add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT); + printk(KERN_NOTICE "COBRA5282 flash device initialized\n"); + return 0; + } + + iounmap((void *)flagadm_map.virt); + return -ENXIO; +} + +static void __exit cleanup_flagadm(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (flagadm_map.virt) { + iounmap((void *)flagadm_map.virt); + flagadm_map.virt = 0; + } +} + +module_init(init_flagadm); +module_exit(cleanup_flagadm); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Boris Koprinarov "); +MODULE_DESCRIPTION("MTD map driver for COBRA5282 board"); diff --git a/drivers/mtd/maps/cobra5329.c b/drivers/mtd/maps/cobra5329.c new file mode 100644 index 00000000..a7d236c0 --- /dev/null +++ b/drivers/mtd/maps/cobra5329.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006, emlix, Thomas Brinker + * + * Handle mapping of the flash on the COBRA5329 boards + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +#define WINDOW_ADDR 0x00000000 +#define WINDOW_SIZE 0x01000000 + +static struct mtd_info *mymtd; + +static struct map_info cobra5329_map = { + .name = "COBRA5329Flash", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, +}; + +static struct mtd_partition cobra5329_partitions[] = +{ + { + .name = "bootloader", + .size = 1*1024*1024, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE + }, { + .name = "kernel", + .size = 6*1024*1024, + .offset = MTDPART_OFS_APPEND, + //.mask_flags = MTD_WRITEABLE + }, { + .name = "data", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND + } +}; + +int __init init_cobra5329mtd(void) +{ + printk(KERN_NOTICE "Cobra5329 flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + cobra5329_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); +/* +Because of the odd place of flash we cannot check if ioremap has succeded + if (!cobra5329_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } +*/ + simple_map_init(&cobra5329_map); + mymtd = do_map_probe("cfi_probe", &cobra5329_map); + + if (mymtd) { + mymtd->owner = THIS_MODULE; + add_mtd_partitions(mymtd, cobra5329_partitions, NB_OF(cobra5329_partitions)); + return 0; + } else + printk("%s: do_map_probe() returned 0\n",__FUNCTION__); + +// iounmap((void *)cobra5329_map.virt); + return -ENXIO; +} + +static void __exit cleanup_cobra5329mtd(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (cobra5329_map.virt) { + iounmap((void *)cobra5329_map.virt); + cobra5329_map.virt = 0; + } +} + +module_init(init_cobra5329mtd); +module_exit(cleanup_cobra5329mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Brinker "); +MODULE_DESCRIPTION("MTD map driver for Cobra5329 boards"); diff --git a/drivers/mtd/maps/dm270-flash.c b/drivers/mtd/maps/dm270-flash.c new file mode 100644 index 00000000..d0410651 --- /dev/null +++ b/drivers/mtd/maps/dm270-flash.c @@ -0,0 +1,230 @@ +/* + * drivers/mtd/maps/dm270-flash.c + * + * Flash memory access on TI TMS320DM270 based devices + * + * Derived from drivers/mtd/maps/omap-toto-flash.c + * + * Copyright (C) 2004 Chee Tim Loh + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#ifndef CONFIG_MACH_DM270 +# error This is for DM270 architecture only! +#endif + +#define DM270_FLASH_BUSWIDTH 2 + +static const char *dm270_partition_types[] = { +#ifdef CONFIG_MTD_CMDLINE_PARTS + "cmdlinepart", +#endif +#ifdef CONFIG_MTD_REDBOOT_PARTS + "RedBoot", +#endif + NULL, +}; + +static struct map_info dm270_map_flash = { + .name = "DM270 flash", + .size = CONFIG_FLASH_SIZE, + .phys = CONFIG_FLASH_MEM_BASE, + .bankwidth = DM270_FLASH_BUSWIDTH, +}; + +/* + * Here are partition information for all known DM270-based devices. + * See include/linux/mtd/partitions.h for definition of the mtd_partition + * structure. + * + * The *_max_flash_size is the maximum possible mapped flash size which + * is not necessarily the actual flash size. It must be no more than + * the value specified in the "struct map_desc *_io_desc" mapping + * definition for the corresponding machine. + */ + +/* + * 1xToshiba TC58FVB160AFT-70 16-MBIT (2Mx8 bits/1Mx16 bits) CMOS FLASH MEMORY + * Block erase architecture: + * 1x16 Kbytes / 2x8 Kbytes / 1x32 Kbytes / 31x64 Kbytes + */ +#ifdef CONFIG_BOARD_XEVMDM270GHK +static struct mtd_partition dm270_partitions[] = { + { + .name = "bootloader", + .size = 0x20000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "kernel", + .size = 0xc0000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "rootfs", + .size = 0x110000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0, /* read-write */ + }, { + .name = "bootloader params", + .size = 0x10000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +}; +#elif defined(CONFIG_BOARD_IMPLDM270VP4) +static struct mtd_partition dm270_partitions[] = { + { + .name = "bootloader", + .size = 0x30000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "kernel", + .size = 0xa0000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "rootfs", + .size = 0x1b0000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0, /* read-write */ + }, { + .name = "data", + .size = 0x570000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0, /* read-write */ + }, { + .name = "bootloader params", + .size = 0x10000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +}; +#else +# error You have not specified your target board! +#endif + +static struct mtd_partition *parsed_parts; + +static struct mtd_info *dm270_flash_mtd; + +static int __init +dm270_init_flash (void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + const char *part_type; + + /* + * Static partition definition selection + */ + part_type = "static"; + + parts = dm270_partitions; + nb_parts = ARRAY_SIZE(dm270_partitions); + dm270_map_flash.virt = phys_to_virt(dm270_map_flash.phys); + + simple_map_init(&dm270_map_flash); + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "DM270 flash: probing %d-bit flash bus\n", + dm270_map_flash.bankwidth*8); + dm270_flash_mtd = do_map_probe("cfi_probe", &dm270_map_flash); + if (!dm270_flash_mtd) { + return -ENXIO; + } + dm270_flash_mtd->owner = THIS_MODULE; + + /* + * Dynamic partition selection stuff (might override the static ones) + */ + if (dm270_partition_types[0]) { + parsed_nr_parts = parse_mtd_partitions(dm270_flash_mtd, + dm270_partition_types, &parsed_parts, + CONFIG_FLASH_MEM_BASE); + } + if (parsed_nr_parts > 0) { + part_type = "dynamic"; + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } + + if (nb_parts == 0) { + printk(KERN_NOTICE "DM270 flash: no partition info available," + "registering whole flash at once\n"); + if (add_mtd_device(dm270_flash_mtd)) { + return -ENXIO; + } + } else { + printk(KERN_NOTICE "Using %s partition definition\n", + part_type); + return add_mtd_partitions(dm270_flash_mtd, parts, nb_parts); + } + return 0; +} + +static int __init +dm270_mtd_init(void) +{ + int status; + + if ((status = dm270_init_flash())) { + printk(KERN_ERR "DM270 Flash: unable to init map for DM270 flash\n"); + } + return status; +} + +static void __exit +dm270_mtd_cleanup(void) +{ + if (dm270_flash_mtd) { + del_mtd_partitions(dm270_flash_mtd); + map_destroy(dm270_flash_mtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(dm270_mtd_init); +module_exit(dm270_mtd_cleanup); + +MODULE_AUTHOR("Chee Tim Loh "); +MODULE_DESCRIPTION("DM270 CFI map driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/em1110.c b/drivers/mtd/maps/em1110.c new file mode 100644 index 00000000..bceef668 --- /dev/null +++ b/drivers/mtd/maps/em1110.c @@ -0,0 +1,102 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +#define UC7110_FLASH_SIZE 0x00400000 +#define WINDOW_SIZE UC7110_FLASH_SIZE + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x100000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x100000 /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1110 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("victor.yu@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the EM1110-LX"); diff --git a/drivers/mtd/maps/em1220.c b/drivers/mtd/maps/em1220.c new file mode 100644 index 00000000..ea0b206b --- /dev/null +++ b/drivers/mtd/maps/em1220.c @@ -0,0 +1,103 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define WINDOW_SIZE 0x00800000 +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ (0x280000-RW_PART0_SZ) /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1220 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the EM1220-LX"); diff --git a/drivers/mtd/maps/em1220_dlin.c b/drivers/mtd/maps/em1220_dlin.c new file mode 100644 index 00000000..cec30d56 --- /dev/null +++ b/drivers/mtd/maps/em1220_dlin.c @@ -0,0 +1,103 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define WINDOW_SIZE 0x00800000 +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ (0x280000-RW_PART0_SZ) /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1220 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the EM1220-LX for DLin ODM"); diff --git a/drivers/mtd/maps/em1240.c b/drivers/mtd/maps/em1240.c new file mode 100644 index 00000000..4bb8edbe --- /dev/null +++ b/drivers/mtd/maps/em1240.c @@ -0,0 +1,103 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define WINDOW_SIZE 0x00800000 +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ (0x280000-RW_PART0_SZ) /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1240 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7110-LX Version 2"); diff --git a/drivers/mtd/maps/em1240_ivtc.c b/drivers/mtd/maps/em1240_ivtc.c new file mode 100644 index 00000000..a3b98e46 --- /dev/null +++ b/drivers/mtd/maps/em1240_ivtc.c @@ -0,0 +1,104 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +//#define WINDOW_SIZE (0x00800000*4) +#define WINDOW_SIZE (0x00800000) +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ (0x280000-RW_PART0_SZ) /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1240 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7110-LX Version 2"); diff --git a/drivers/mtd/maps/em1240_mt.c b/drivers/mtd/maps/em1240_mt.c new file mode 100644 index 00000000..01d29ce2 --- /dev/null +++ b/drivers/mtd/maps/em1240_mt.c @@ -0,0 +1,103 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define WINDOW_SIZE 0x01000000 +#define UC7110_FLASH_SIZE 0x01000000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x3c0000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x600000 /* root file system */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "EM1240 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7110-LX Version 2"); diff --git a/drivers/mtd/maps/epcs_map.c b/drivers/mtd/maps/epcs_map.c new file mode 100644 index 00000000..78990b6e --- /dev/null +++ b/drivers/mtd/maps/epcs_map.c @@ -0,0 +1,157 @@ +/* + * + * Mappings into EPCS Configuration Flash device by Altera + * + * Copyright (C) 2006 FPS-Tech (http://www.fps-tech.net) + * Author: Jai Dhar, contact@fps-tech.net (jdhar) + * + * Adapted from physmap.c + * + * - Driver to map partitions into EPCS Configuration device + * - Map Size should get set by epcs_probe when it detects a chip + * - IOREMAP is done for maximum size possible (64Mbit) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../chips/epcs.h" + +#define BUSWIDTH 1 + +static struct mtd_info *mymtd; + +struct map_info alt_epcs_map = { + .name = "Altera EPCS Flash", + .phys = na_epcs_controller, + .size = 0, + .bankwidth = BUSWIDTH, +}; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition *mtd_parts; +static int mtd_parts_nb; + +static int num_physmap_partitions; +static struct mtd_partition epcs_partitions[] = +{ + { + .name = "small_part", + .size = 0x200000, + .offset = 0x400000, + }, + { + .name = "big_part", + .size = 0x200000, + .offset = 0x600000, + } +}; + +static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; + +#define NUM_PARTITIONS (sizeof(epcs_partitions)/sizeof(struct mtd_partition)) + +#endif /* CONFIG_MTD_PARTITIONS */ + +static int __init init_epcsmap(void) +{ + static const char *rom_probe_types[] = { "epcs", NULL }; + const char **type; + + /* Not sure about this, but since IOREMAP looks like it needs to happen before the chip is probed, + * the maximum space (64Mbit) must be allocated */ + alt_epcs_map.virt = (unsigned long *)ioremap_nocache(na_epcs_controller, na_epcs_controller_size); + + /* + if (!physmap_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + }*/ + + simple_map_init(&alt_epcs_map); + + mymtd = NULL; + type = rom_probe_types; + for(; !mymtd && *type; type++) { + + #if EPCS_DEBUG1 + printk(KERN_NOTICE "Probing for %s\n",*type); + #endif + + mymtd = do_map_probe(*type, &alt_epcs_map); + } + if (mymtd) { + mymtd->owner = THIS_MODULE; + + #if EPCS_DEBUG1 + printk(KERN_NOTICE "alt_epcs flash device: %d Kbytes at 0x%X\n", (u_int) alt_epcs_map.size/1024, (u_int) alt_epcs_map.phys); + #endif + +#ifdef CONFIG_MTD_PARTITIONS + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + &mtd_parts, 0); + + if (mtd_parts_nb > 0) + { + add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + return 0; + } + + if (NUM_PARTITIONS != 0) + { + #if EPCS_DEBUG1 + printk(KERN_NOTICE "Using Altera EPCS partition definition\n"); + #endif + + add_mtd_partitions (mymtd, epcs_partitions, NUM_PARTITIONS); + return 0; + } + +#endif + add_mtd_device(mymtd); + + return 0; + } + else + { + printk(KERN_NOTICE "No Partitions found on EPCS Device\n"); + } + + iounmap(alt_epcs_map.virt); + return -ENXIO; +} + +static void __exit cleanup_epcsmap(void) +{ +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_parts_nb) { + del_mtd_partitions(mymtd); + kfree(mtd_parts); + } else if (num_physmap_partitions) { + del_mtd_partitions(mymtd); + } else { + del_mtd_device(mymtd); + } +#else + del_mtd_device(mymtd); +#endif + map_destroy(mymtd); + + iounmap(alt_epcs_map.virt); + alt_epcs_map.virt = NULL; +} + +module_init(init_epcsmap); +module_exit(cleanup_epcsmap); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jai Dhar "); +MODULE_DESCRIPTION("Altera EPCS Map Device"); diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 7a828e3e..3189fb7e 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -1,5 +1,5 @@ /* - * $Id: ixp4xx.c,v 1.13 2005/11/16 16:23:21 dvrabel Exp $ + * $Id: ixp4xx.c,v 1.9 2006/11/30 02:03:18 gerg Exp $ * * drivers/mtd/maps/ixp4xx.c * diff --git a/drivers/mtd/maps/m520x.c b/drivers/mtd/maps/m520x.c new file mode 100644 index 00000000..86ca368a --- /dev/null +++ b/drivers/mtd/maps/m520x.c @@ -0,0 +1,241 @@ +/* + * + * Normal mappings of chips in physical memory. + * + * Copyright (C) 2005, Freescale Semiconductor (Matt.Waddel@freescale.com) + * Copyright (C) 2005, Intec Automation Inc. (mike@steroidmicros.com) + * Copyright (C) 2001-2002, David McCullough + * + * Based on snapgear-uc.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern dev_t ROOT_DEV; + +#define WINDOW_ADDR 0x00000000 +#define WINDOW_SIZE 0x00200000 +#define BANKWIDTH 2 + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *ram_mtdinfo; +static struct map_info m520x_ram_map = { + .name = "RAM", +}; +static struct mtd_partition m520x_romfs[] = { + { + .name = "Romfs" + } +}; + +static struct mtd_info *flash_mtdinfo; +struct map_info m520x_flash_map = { + .name = "Am29BDD160G 2.5v flash device (2MB)", + .size = WINDOW_SIZE, + .bankwidth = BANKWIDTH +}; +static struct mtd_partition m520x_partitions[] = { + { + .name = "dBUG (256K)", + .size = 0x40000, + .offset = 0x00000 + }, + { + .name = "User FS (1792K)", + .size = 0x1C0000, + .offset = 0x40000 + } +}; + +/**************************************************************************** + * + * Find the MTD device with the given name + * + ****************************************************************************/ + +static struct mtd_info +*get_mtd_named(char *name) +{ + int i; + struct mtd_info *mtd; + + for (i = 0; i < MAX_MTD_DEVICES; i++) { + mtd = get_mtd_device(NULL, i); + + if (mtd) { + if (strcmp(mtd->name, name) == 0) + return(mtd); + put_mtd_device(mtd); + } + } + return(NULL); +} + + +static int +m520x_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf) +{ + struct map_info *map = (struct map_info *) mtd->priv; + *mtdbuf = (u_char *) (map->map_priv_1 + (int)from); + *retlen = len; + return(0); +} + + +static int __init +m520x_probe(int type, unsigned long addr, int size, int bankwidth) +{ + static struct mtd_info *mymtd; + struct map_info *map_ptr; + + if (type) + map_ptr = &m520x_ram_map; + else + map_ptr = &m520x_flash_map; + + map_ptr->bankwidth = bankwidth; + map_ptr->map_priv_2 = addr; + map_ptr->phys = addr; + map_ptr->size = size; + + printk(KERN_NOTICE "m520xevb %s probe(0x%lx,%x,%x): %lx at %lx\n", + type ? "ram":"flash", addr, size, bankwidth, + map_ptr->size, map_ptr->map_priv_2); + + map_ptr->virt = (unsigned long) + ioremap_nocache(map_ptr->map_priv_2, map_ptr->size); + + simple_map_init(map_ptr); + if (type) + mymtd = do_map_probe("map_ram", map_ptr); + else + mymtd = do_map_probe("cfi_probe", map_ptr); + + if (!mymtd) { + iounmap((void *)map_ptr->map_priv_1); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + mymtd->point = m520x_point; + mymtd->priv = map_ptr; + + if (type) { + ram_mtdinfo = mymtd; + add_mtd_partitions(mymtd, m520x_romfs, NB_OF(m520x_romfs)); + } else { + flash_mtdinfo = mymtd; + add_mtd_partitions(mymtd, m520x_partitions, + sizeof(m520x_partitions) / sizeof(struct mtd_partition)); + } + return(0); +} + + +/* + * Initialize the mtd devices + */ + +int __init init_m520x(void) +{ + int rc = -1; + struct mtd_info *mtd; + extern char _ebss; + + rc = m520x_probe( 0, WINDOW_ADDR, WINDOW_SIZE, BANKWIDTH); + + /* Map in the filesystem from RAM last so that, if the filesystem + * is not in RAM for some reason we do not change the minor/major + * for the flash devices + */ +#ifndef CONFIG_ROMFS_FROM_ROM + if (0 != m520x_probe( 1, (unsigned long)&_ebss, + PAGE_ALIGN(*(unsigned long *)(&_ebss + 8)), 4)) + printk("Failed to probe RAM filesystem\n"); +#else + { + unsigned long start_area; + unsigned char *sp, *ep; + size_t len; + + start_area = (unsigned long) &_ebss; + + /* If romfs is in flash use it to boot */ + if (strncmp((char *) start_area, "-rom1fs-", 8) != 0) { + mtd = get_mtd_named("Image"); + if (mtd && mtd->point) { + if ((*mtd->point)(mtd, 0, mtd->size, &len, &sp) == 0){ + ep = sp + len; + while (sp < ep && strncmp(sp,"-rom1fs-",8) != 0) + sp++; + if (sp < ep) + start_area = (unsigned long) sp; + } + } + if (mtd) + put_mtd_device(mtd); + } + if (0 != m520x_probe(1, start_area, + PAGE_ALIGN(*(unsigned long *)(start_area + 8)), 4)) + printk("Failed to probe RAM filesystem\n"); + } +#endif + + mtd = get_mtd_named("Romfs"); + if (mtd) { + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + put_mtd_device(mtd); + } else + printk("%s: Failed to make root filesystem\n", __FUNCTION__); + + mtd = get_mtd_named("User FS (1792K)"); + if (mtd) { + blk_register_region(MKDEV(MTD_BLOCK_MAJOR, mtd->index), MAX_MTD_DEVICES, + THIS_MODULE, m520x_probe, NULL, NULL); + put_mtd_device(mtd); + } else + printk("%s: Failed to flash filesystem\n", __FUNCTION__); + + return(rc); +} + +static void __exit cleanup_m520x(void) +{ + if (flash_mtdinfo) { + del_mtd_partitions(flash_mtdinfo); + map_destroy(flash_mtdinfo); + flash_mtdinfo = NULL; + } + if (ram_mtdinfo) { + del_mtd_partitions(ram_mtdinfo); + map_destroy(ram_mtdinfo); + ram_mtdinfo = NULL; + } + if (m520x_ram_map.map_priv_1) { + iounmap((void *)m520x_ram_map.map_priv_1); + m520x_ram_map.map_priv_1 = 0; + } + if (m520x_flash_map.map_priv_1) { + iounmap((void *)m520x_flash_map.map_priv_1); + m520x_flash_map.map_priv_1 = 0; + } + +} + +module_init(init_m520x); +module_exit(cleanup_m520x); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("MTD map for M520xEVB"); diff --git a/drivers/mtd/maps/microtronix.c b/drivers/mtd/maps/microtronix.c new file mode 100644 index 00000000..db299a3f --- /dev/null +++ b/drivers/mtd/maps/microtronix.c @@ -0,0 +1,129 @@ +/* + * Normal mappings of Microtronix ukit flash in physical memory + * Derived from physmap.c, by Microtronix Datacom Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* map solutions */ +#define WINDOW_ADDR na_flash_kernel +#define WINDOW_SIZE na_flash_kernel_size +#define BUSWIDTH 2 + +static struct mtd_info *mymtd; + + +struct map_info microtronix_map = { + .name = "Microtronix map", + .size = WINDOW_SIZE, + .bankwidth = BUSWIDTH, + .phys = WINDOW_ADDR, +}; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition *mtd_parts; +static int mtd_parts_nb; + +static struct mtd_partition microtronix_partitions[] = { + { + .name = "romfs", + .size = 0x600000, + .offset = 0x200000, + },{ + .name = "loader/kernel", + .size = 0x200000, + .offset = 0, + } +}; + +#define NUM_PARTITIONS (sizeof(microtronix_partitions)/sizeof(struct mtd_partition)) +const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL}; + +#endif /* CONFIG_MTD_PARTITIONS */ + +int __init init_microtronix_map(void) +{ + static const char *flash_probe_types[] = {"cfi_probe", "jedec_probe", 0 }; + const char **type; + + microtronix_map.virt = (unsigned long *)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); +/* + if (!microtronix_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } +*/ + simple_map_init(µtronix_map); + + mymtd = 0; + type = flash_probe_types; + for(; !mymtd && *type; type++) { + mymtd = do_map_probe(*type, µtronix_map); + } + if (mymtd) { + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + &mtd_parts, 0); + + if (mtd_parts_nb > 0) + { + add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + return 0; + } + + if (NUM_PARTITIONS != 0) + { + printk(KERN_NOTICE + "Using Microtronix development partition definition\n"); + add_mtd_partitions (mymtd, microtronix_partitions, NUM_PARTITIONS); + return 0; + } + +#endif + add_mtd_device(mymtd); + + return 0; + } + + iounmap((void *)microtronix_map.virt); + return -ENXIO; +} + +static void __exit cleanup_microtronix_map(void) +{ +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_parts_nb) { + del_mtd_partitions(mymtd); + kfree(mtd_parts); + } else if (NUM_PARTITIONS) { + del_mtd_partitions(mymtd); + } else { + del_mtd_device(mymtd); + } +#else + del_mtd_device(mymtd); +#endif + map_destroy(mymtd); + + iounmap((void *)microtronix_map.virt); + microtronix_map.virt = 0; +} + +module_init(init_microtronix_map); +module_exit(cleanup_microtronix_map); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Microtronix Datacom"); +MODULE_DESCRIPTION("MTD map driver for Microtronix ukit"); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index f9e8e5bc..3454484c 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -5,8 +5,6 @@ * * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) - * - * $Id: nettel.c,v 1.12 2005/11/29 14:30:00 gleixner Exp $ */ /****************************************************************************/ @@ -15,6 +13,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 5d3c7545..5f6146c3 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include @@ -47,7 +50,6 @@ struct platram_info { struct mtd_info *mtd; struct map_info map; struct mtd_partition *partitions; - struct resource *area; struct platdata_mtd_ram *pdata; }; @@ -96,10 +98,9 @@ static int platram_remove(struct platform_device *pdev) if (info->mtd) { #ifdef CONFIG_MTD_PARTITIONS - if (info->partitions) { - del_mtd_partitions(info->mtd); + del_mtd_partitions(info->mtd); + if (info->partitions) kfree(info->partitions); - } #endif del_mtd_device(info->mtd); map_destroy(info->mtd); @@ -111,11 +112,6 @@ static int platram_remove(struct platform_device *pdev) /* release resources */ - if (info->area) { - release_resource(info->area); - kfree(info->area); - } - if (info->map.virt != NULL) iounmap(info->map.virt); @@ -179,15 +175,6 @@ static int platram_probe(struct platform_device *pdev) info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pdev->name; info->map.bankwidth = pdata->bankwidth; - /* register our usage of the memory area */ - - info->area = request_mem_region(res->start, info->map.size, pdev->name); - if (info->area == NULL) { - dev_err(&pdev->dev, "failed to request memory region\n"); - err = -EIO; - goto exit_free; - } - /* remap the memory area */ info->map.virt = ioremap(res->start, info->map.size); @@ -221,27 +208,34 @@ static int platram_probe(struct platform_device *pdev) #ifdef CONFIG_MTD_PARTITIONS if (pdata->nr_partitions > 0) { - const char **probes = { NULL }; - - if (pdata->probes) - probes = (const char **)pdata->probes; - - err = parse_mtd_partitions(info->mtd, probes, + err = add_mtd_partitions(info->mtd, pdata->partitions, + pdata->nr_partitions); + if (err < 0) + goto exit_free; + } else if (pdata->probes) { + err = parse_mtd_partitions(info->mtd, pdata->probes, &info->partitions, 0); if (err > 0) { err = add_mtd_partitions(info->mtd, info->partitions, err); } + if (err < 0) + goto exit_free; } #endif /* CONFIG_MTD_PARTITIONS */ if (add_mtd_device(info->mtd)) { dev_err(&pdev->dev, "add_mtd_device() failed\n"); err = -ENOMEM; + goto exit_free; } dev_info(&pdev->dev, "registered mtd device\n"); - return err; + + if (pdata->root_dev) + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, info->mtd->index); + + return 0; exit_free: platram_remove(pdev); diff --git a/drivers/mtd/maps/snaparm.c b/drivers/mtd/maps/snaparm.c new file mode 100644 index 00000000..8c47b8c4 --- /dev/null +++ b/drivers/mtd/maps/snaparm.c @@ -0,0 +1,827 @@ +/****************************************************************************/ + +/* + * snaparm.c -- mappings for SnapGear ARM based boards + * + * (C) Copyright 2000-2005, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2001-2005, SnapGear (www.snapgear.com) + * + * I expect most SnapGear ARM based boards will have similar + * flash arrangements. So this map driver can handle them all. + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ + +static struct mtd_info *sg_mtd; +static struct resource *sg_res; + +/* + * This is the ARM method of setting up the initrd memory region now. + */ +extern unsigned long phys_initrd_start; + +/****************************************************************************/ + +/* First the fixed-configuration platforms */ +#if defined(CONFIG_MACH_SE5100) +#define FLASH_ADDR 0x50000000 +#define FLASH_SIZE 0x02000000 +#define FLASH_WIDTH 2 + +#define BOOT_OFFSET 0x00000000 +#define BOOT_SIZE 0x00040000 + +#define RECOVER_OFFSET 0x00040000 +#define RECOVER_SIZE 0x00800000 + +#define KERNEL_OFFSET (BOOT_SIZE + RECOVER_SIZE) +#define KERNEL_SIZE 0x00180000 +#define CONFIG_SIZE 0x00020000 +#define NG_CONFIG_SIZE 0x00200000 +#define NG_VAR_SIZE 0x00200000 + +#define ROOTFS_SIZE (FLASH_SIZE - BOOT_SIZE - KERNEL_SIZE - CONFIG_SIZE - \ + NG_CONFIG_SIZE - NG_VAR_SIZE - RECOVER_SIZE) + +static struct mtd_partition sg_partitions[] = { + /* + * if you change the names of these, check the table below + * for unlocking the flash as well + */ + { + name: "SnapGear kernel", + offset: KERNEL_OFFSET, + size: KERNEL_SIZE, + }, + { + name: "SnapGear filesystem", + offset: KERNEL_OFFSET + KERNEL_SIZE, + size: ROOTFS_SIZE, + }, + { + name: "SnapGear config", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE, + size: CONFIG_SIZE + }, + { + name: "SnapGear Extra config", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE + CONFIG_SIZE, + size: NG_CONFIG_SIZE + }, + { + name: "SnapGear Extra var", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE + CONFIG_SIZE + NG_CONFIG_SIZE, + size: NG_VAR_SIZE + }, + { + name: "SnapGear image partition", + offset: KERNEL_OFFSET, + size: KERNEL_SIZE + ROOTFS_SIZE, + }, + { + name: "SnapGear BIOS config", + offset: BOOT_SIZE / 2, + size: BOOT_SIZE / 2, + }, + { + name: "SnapGear BIOS", + offset: 0, + size: BOOT_SIZE, + }, + { + name: "SnapGear Recover", + offset: RECOVER_OFFSET, + size: RECOVER_SIZE, + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, +}; + +#elif defined(CONFIG_MACH_IPD) + +#define FLASH_ADDR 0x00000000 +#define FLASH_SIZE 0x01000000 +#define FLASH_WIDTH 2 + +static struct mtd_partition sg_partitions[] = { + { + name: "SnapGear Boot Loader", + offset: 0, + size: 0x00020000 + }, + { + name: "SnapGear System Data", + offset: 0x00020000, + size: 0x00020000 + }, + { + name: "SnapGear non-volatile configuration", + offset: 0x00040000, + size: 0x00020000 + }, + { + name: "SnapGear image", + offset: 0x00060000, + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, +}; + +#elif defined(CONFIG_MACH_CM4008) + +#define FLASH_ADDR 0x02000000 +#define FLASH_SIZE 0x00800000 +#define FLASH_WIDTH 1 + +#elif defined(CONFIG_MACH_CM41xx) + +#define FLASH_ADDR 0x02000000 +#define FLASH_SIZE 0x01000000 +#define FLASH_WIDTH 1 + +#else + +/* Now the dynamic-configuration platforms (based on machine_arch_type) */ +#define DYNAMIC_SGARM_CONFIG + +typedef struct { + unsigned long type; /* machine_arch_type */ + unsigned long addr; /* Physical flash address */ + unsigned long size; /* Maximum flash size */ + unsigned long configsize; /* Size of the config partition */ + unsigned width; /* Flash bus width */ +} flash_layout_t; + +static const flash_layout_t flash_layout[] = { +#if defined(CONFIG_MACH_SE4000) + { .type = MACH_TYPE_SE4000, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x20000 }, +#endif +#if defined(CONFIG_MACH_IVPN) + { .type = MACH_TYPE_IVPN, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x20000 }, +#endif +#if defined(CONFIG_MACH_SG560) || defined (CONFIG_MACH_SGARMAUTO) + { .type = MACH_TYPE_SG560, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x80000 }, +#endif +#if defined(CONFIG_MACH_SG580) || defined (CONFIG_MACH_SGARMAUTO) + { .type = MACH_TYPE_SG580, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x100000 }, +#endif +#if defined(CONFIG_MACH_SG590) || defined (CONFIG_MACH_SGARMAUTO) + { .type = MACH_TYPE_SG590, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x100000 }, +#endif +#if defined(CONFIG_MACH_SG640) || defined (CONFIG_MACH_SGARMAUTO) + { .type = MACH_TYPE_SG640, .addr = 0x50000000, .size = 0x01000000, .width = 2, .configsize = 0x100000 }, +#endif +#if defined(CONFIG_MACH_SG565) || defined (CONFIG_MACH_SGARMAUTO) + { .type = MACH_TYPE_SG565, .addr = 0x50000000, .size = 0x01000000, .width = 1, .configsize = 0x100000 }, +#endif +#if defined(CONFIG_MACH_SG720) + { .type = MACH_TYPE_SG720, .addr = 0x50000000, .size = 0x01000000, .width = 1, .configsize = 0 }, +#endif +#if defined(CONFIG_MACH_SG8100) + { .type = MACH_TYPE_SG8100, .addr = 0x50000000, .size = 0x02000000, .width = 2, .configsize = 0x100000 }, +#endif +#if defined(CONFIG_MACH_SHIVA1100) + { .type = MACH_TYPE_SHIVA1100, .addr = 0x50000000, .size = 0x01000000, .width = 1, .configsize = 0x20000 }, +#endif +#if defined(CONFIG_MACH_LITE300) + { .type = MACH_TYPE_LITE300, .addr = 0x02000000, .size = 0x00800000, .width = 1, .configsize = 0x20000 }, +#endif +#if defined(CONFIG_MACH_SE4200) + { .type = MACH_TYPE_SE4200, .addr = 0x02000000, .size = 0x00800000, .width = 1, .configsize = 0x20000 }, +#endif +#if defined(CONFIG_MACH_EP9312) + { .type = MACH_TYPE_EP9312, .addr = 0x60000000, .size = 0x00800000, .width = 2, .configsize = 0x20000 }, +#endif +}; + +#endif + +/****************************************************************************/ + +//#define SNAPARM_DEBUG 1 +#ifdef SNAPARM_DEBUG +#define DPRINTK printk +#else +#define DPRINTK(...) +#endif + +/****************************************************************************/ + +/* + * Define some access helper macros. On different architectures + * we have to deal with multi-byte quanitites, read/write buffers, + * and other architectural details a little differently. These + * macros try to abstract that as much as possible to keep the + * code clean. + */ + +#ifdef CONFIG_ARCH_KS8695 +#include +/* + * The bus read and write buffers can potenitially coalesce read and + * write bus cycles to the same address, thus dropping real cycles + * when talking to IO type devices. We need to flush those buffers + * when doing flash reading/writing. + * + * Walk through a small section of memory avoiding the cache so that we + * can keep the flash running smoothly. Using the write buffer enable + * disable seems tocause nasty bus junk, sodon't use them. + */ +static void invalidate_buffer(void) +{ + static unsigned char buf[32]; + unsigned char cpy[sizeof(buf)]; + + memset(buf, 0, sizeof(buf)); + clean_dcache_area(buf, sizeof(buf)); + memcpy(cpy, buf, sizeof(buf)); + clean_dcache_area(buf, sizeof(buf)); +} +#define readpreflush(x) invalidate_buffer() +#define writepreflush(x) invalidate_buffer() + +#define CONFIG_LOCK_MULTIBYTE +static DEFINE_SPINLOCK(multibyte_lock); +#define initlock() unsigned long flags; +#define getlock() spin_lock_irqsave(&multibyte_lock, flags) +#define releaselock() spin_unlock_irqrestore(&multibyte_lock, flags) +#endif /* CONFIG_ARCH_KS8695 */ + + +/* + * We are not entirely sure why, but on the iVPN the timing _between_ + * access to the flash causes problems with other bus activity on the + * expansion bus. Namely the CompactFlash WiFi card. Delaying 1us + * is enough to clean up the cycles. + */ +#ifdef CONFIG_MACH_IVPN +#define readpreflush(x) udelay(1) +#define readpostflush(x) udelay(1) +#define writepreflush(x) udelay(1) +#define writepostflush(x) udelay(1) + +#define CONFIG_LOCK_MULTIBYTE +static DEFINE_SPINLOCK(multibyte_lock); +#define initlock() unsigned long flags; +#define getlock() spin_lock_irqsave(&multibyte_lock, flags) +#define releaselock() spin_unlock_irqrestore(&multibyte_lock, flags) +#endif /* CONFIG_MACH_IVPN */ + + +/* + * Now default any macros that are not used. + */ +#ifndef readpreflush +#define readpreflush(x) +#endif +#ifndef readpostflush +#define readpostflush(x) +#endif +#ifndef writepreflush +#define writepreflush(x) +#endif +#ifndef writepostflush +#define writepostflush(x) +#endif +#ifndef initlock +#define initlock() +#endif +#ifndef getlock +#define getlock() +#endif +#ifndef releaselock +#define releaselock() +#endif + +/****************************************************************************/ + +static map_word sg_read(struct map_info *map, unsigned long ofs) +{ + map_word res; + readpreflush(map->virt + ofs); + if (map_bankwidth(map) == 1) + res.x[0] = __raw_readb(map->virt + ofs); + else + res.x[0] = __raw_readw(map->virt + ofs); + readpostflush(map->virt + ofs); + DPRINTK("%s(0x%x) = 0x%x\n", __FUNCTION__, (u32)ofs, (u32)res.x[0]); + return res; +} + +static void sg_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + void __iomem *p8; + union { + __u32 l; + __u8 c[4]; + } data; + __u8 *dp; + initlock(); + + DPRINTK("%s(to=0x%x, from=0x%x, len=%d)\n", __FUNCTION__, + (__u32)to, (__u32)from, (__u32)len); + + if (len <= 0) + return; + + getlock(); + + p8 = (map->virt + from); + dp = (__u8 *) to; + + /* + * read until the pointer to flash is on a 32 bit boundary + */ + while (len > 0 && (((unsigned long) p8) & 3)) { + readpreflush(p8); + *dp++ = __raw_readb(p8); + readpostflush(p8); + p8++; + len--; + } + /* + * The Xscale will do a back-to-back cycle on flash if we read + * 2 16bit values as a single 32 bit quantity, this is much faster + * than two normal 16bit cycles + */ + while (len & ~3) { + readpreflush(p8); + data.l = __raw_readl(p8); + *dp++ = data.c[0]; + *dp++ = data.c[1]; + *dp++ = data.c[2]; + *dp++ = data.c[3]; + readpostflush(p8); + p8 += sizeof(__u32); + len -= sizeof(__u32); + } + /* + * clean up and non-aligned reads at the end + */ + while (len > 0) { + readpreflush(p8); + *dp++ = __raw_readb(p8); + readpostflush(p8); + p8++; + len--; + } + + releaselock(); +} + +static void sg_write(struct map_info *map, map_word d, unsigned long adr) +{ + DPRINTK("%s(0x%x,0x%x)\n", __FUNCTION__, (u32)d.x[0], (u32)adr); + writepreflush(map->virt + adr); + if (map_bankwidth(map) == 1) + __raw_writeb(d.x[0], map->virt + adr); + else + __raw_writew(d.x[0], map->virt + adr); + writepostflush(map->virt + adr); +} + +static void sg_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + unsigned int i; + initlock(); + + DPRINTK("%s(to=0x%x,from=0x%x,len=%d)\n", __FUNCTION__, + (u32)to, (u32)from, len); + + getlock(); + if (map_bankwidth(map) == 1) { + u8 *src8; + for (src8 = (u8 *) from, i = 0; (i < len); i++) { + writepreflush(map->virt + to + i); + __raw_writeb(*src8++, map->virt + to + i); + writepostflush(map->virt + to + i); + } + } else { + u16 *src16; + for (src16 = (u16 *) from, i = 0; (i < len); i += 2) { + writepreflush(map->virt + to + i); + __raw_writew(*src16++, map->virt + to + i); + writepostflush(map->virt + to + i); + } + } + releaselock(); +} + +/****************************************************************************/ +/* OPENGEAR FLASH */ +/****************************************************************************/ +#if defined(CONFIG_MACH_CM4008) || defined(CONFIG_MACH_CM41xx) + +#define VENDOR "OpenGear" + +/* + * Intel FLASH setup. This is the only flash device, it is the entire + * non-volatile storage (no IDE CF or hard drive or anything else). + */ +static struct map_info sg_map = { + .name = "OpenGear Intel/StrataFlash", + .size = FLASH_SIZE, + .bankwidth = FLASH_WIDTH, + .read = sg_read, + .copy_from = sg_copy_from, + .write = sg_write, + .copy_to = sg_copy_to +}; + +static struct mtd_partition sg_partitions[] = { + { + .name = "U-Boot Loader", + .offset = 0, + .size = 0x00020000 + }, + { + .name = "OpenGear non-volatile configuration", + .offset = 0x00020000, + .size = 0x001e0000 + }, + { + .name = "OpenGear image", + .offset = 0x200000, + }, + { + .name = "OpenGear Intel/StrataFlash", + .offset = 0 + }, +}; + +#else +/****************************************************************************/ +/* SNAPGEAR FLASH */ +/****************************************************************************/ + +#define VENDOR "SnapGear" + +#if defined(CONFIG_MACH_SE5100) +#define VENDOR_ROOTFS "SnapGear filesystem" +#else +#define VENDOR_ROOTFS "SnapGear image" +#endif + +/* + * Intel FLASH setup. This is the only flash device, it is the entire + * non-volatile storage (no IDE CF or hard drive or anything else). + */ +static struct map_info sg_map = { + name: "SnapGear Intel/StrataFlash", +#ifndef DYNAMIC_SGARM_CONFIG + size: FLASH_SIZE, + bankwidth: FLASH_WIDTH, +#endif + read: sg_read, + copy_from: sg_copy_from, + write: sg_write, + copy_to: sg_copy_to +}; + +#ifdef DYNAMIC_SGARM_CONFIG +static unsigned long flash_addr; +#define FLASH_ADDR flash_addr +#endif + +/* Define the flash layout */ +#if defined(CONFIG_MACH_SE5100) +static struct mtd_partition sg_partitions[] = { + /* + * if you change the names of these, check the table below + * for unlocking the flash as well + */ + { + name: "SnapGear kernel", + offset: KERNEL_OFFSET, + size: KERNEL_SIZE, + }, + { + name: "SnapGear filesystem", + offset: KERNEL_OFFSET + KERNEL_SIZE, + size: ROOTFS_SIZE, + }, + { + name: "SnapGear config", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE, + size: CONFIG_SIZE + }, + { + name: "SnapGear Extra config", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE + CONFIG_SIZE, + size: NG_CONFIG_SIZE + }, + { + name: "SnapGear Extra var", + offset: KERNEL_OFFSET + KERNEL_SIZE + ROOTFS_SIZE + CONFIG_SIZE + NG_CONFIG_SIZE, + size: NG_VAR_SIZE + }, + { + name: "SnapGear image partition", + offset: KERNEL_OFFSET, + size: KERNEL_SIZE + ROOTFS_SIZE, + }, + { + name: "SnapGear BIOS config", + offset: BOOT_SIZE / 2, + size: BOOT_SIZE / 2, + }, + { + name: "SnapGear BIOS", + offset: 0, + size: BOOT_SIZE, + }, + { + name: "SnapGear Recover", + offset: RECOVER_OFFSET, + size: RECOVER_SIZE, + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, +}; +#elif defined(CONFIG_MACH_IPD) +static struct mtd_partition sg_partitions[] = { + { + name: "SnapGear Boot Loader", + offset: 0, + size: 0x00020000 + }, + { + name: "SnapGear System Data", + offset: 0x00020000, + size: 0x00020000 + }, + { + name: "SnapGear non-volatile configuration", + offset: 0x00040000, + size: 0x00020000 + }, + { + name: "SnapGear image", + offset: 0x00060000, + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, +}; +#elif defined(CONFIG_MACH_SG720) +static struct mtd_partition sg_partitions[] = { + { + name: "SnapGear Boot Loader", + offset: 0, + size: 0x00080000 + }, + { + name: "SnapGear Tags", + offset: 0x00080000, + size: 0x00080000 + }, + { + name: "SnapGear Log", + offset: 0x00100000, + size: 0x00100000 + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, + { + name: "SnapGear Unused", + offset: 0x00200000, + }, +}; +#else +/* We use a dynamic structure */ +static struct mtd_partition sg_partitions[] = { + { + name: "SnapGear Boot Loader", + offset: 0, + size: 0x00020000 + }, + { + name: "SnapGear non-volatile configuration", + offset: 0x00020000, + /*size: CONFIG_SIZE -- filled in when we know the config size */ + }, + { + name: "SnapGear image", + offset: 0x00020000, /* +CONFIG_SIZE, -- filled in when we know the config size */ + }, + { + name: "SnapGear Intel/StrataFlash", + offset: 0 + }, +}; +#endif + +/****************************************************************************/ +#endif +/****************************************************************************/ + +#define NUM_PARTITIONS (sizeof(sg_partitions)/sizeof(sg_partitions[0])) + +/****************************************************************************/ + +/* + * Set the Intel flash back to read mode. Sometimes MTD leaves the + * flash in status mode, and if you reboot there is no code to + * execute (the flash devices do not get a RESET) :-( + */ +static int sg_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v) +{ + struct cfi_private *cfi = sg_map.fldrv_priv; + int i; + + /* Make sure all FLASH chips are put back into read mode */ + for (i = 0; cfi && i < cfi->numchips; i++) { + cfi_send_gen_cmd(0xff, 0x55, cfi->chips[i].start, &sg_map, + cfi, cfi->device_type, NULL); + } + return NOTIFY_OK; +} + +static struct notifier_block sg_notifier_block = { + sg_reboot_notifier, NULL, 0 +}; + +/****************************************************************************/ + +/* + * Find the MTD device with the given name. + */ + +static int sg_getmtdindex(char *name) +{ + struct mtd_info *mtd; + int i, index; + + index = -1; + for (i = 0; (i < MAX_MTD_DEVICES); i++) { + mtd = get_mtd_device(NULL, i); + if (mtd) { + if (strcmp(mtd->name, name) == 0) + index = mtd->index; + put_mtd_device(mtd); + if (index >= 0) + break; + } + } + return index; +} + +/****************************************************************************/ + +int __init sg_init(void) +{ + int index, rc; + + printk(VENDOR ": MTD flash setup\n"); + + +#ifdef DYNAMIC_SGARM_CONFIG + /* Find the matching entry in the flash_layout table. + * Note that for almost *all* devices, there will be only 1 + */ + for (index = 0; index < sizeof(flash_layout) / sizeof(*flash_layout); index++) { + if (flash_layout[index].type == machine_arch_type) { + break; + } + } + if (index == sizeof(flash_layout) / sizeof(*flash_layout)) { + printk(KERN_WARNING VENDOR ": No matching flash layout for mach type %d, using mach type %lu\n", + machine_arch_type, flash_layout[0].type); + index = 0; + } + + /* Fix up the entries in sg_map */ + sg_map.size = flash_layout[index].size; + sg_map.bankwidth = flash_layout[index].width; + flash_addr = flash_layout[index].addr; + + /* And also fix up the partition table if we have a config partition */ + if (flash_layout[index].configsize) { + sg_partitions[1].size += flash_layout[index].configsize; + sg_partitions[2].offset += flash_layout[index].configsize; + } +#endif + +#if defined(CONFIG_ARCH_IXP4XX) +{ + u32 val; + /* + * enable fast CS0 (Intel flash J3 and P30 compatible values) + * T1=0, T2=2, T3=1, T4=0, T5=0 + * NOTE: a value of "0" implies 1 cycle + * we preserve all the bootloader set values for size etc of the CS + * and only change T1-5 + */ + val = *IXP4XX_EXP_CS0; + val = (val & 0xffff) | 0x80c00000; + /* Enable flash writes */ + val |= IXP4XX_FLASH_WRITABLE; + *IXP4XX_EXP_CS0 = val; +} +#endif + + sg_res = request_mem_region(FLASH_ADDR, sg_map.size, VENDOR " FLASH"); + if (sg_res == NULL) { + printk(VENDOR ": failed memory resource request?\n"); + return -EIO; + } + + /* + * Map flash into our virtual address space. + */ + sg_map.virt = ioremap(FLASH_ADDR, sg_map.size); + if (!sg_map.virt) { + release_mem_region(FLASH_ADDR, sg_map.size); + sg_res = NULL; + printk(VENDOR ": failed to ioremap() flash\n"); + return -EIO; + } + + if ((sg_mtd = do_map_probe("cfi_probe", &sg_map)) == NULL) { + iounmap(sg_map.virt); + release_mem_region(FLASH_ADDR, sg_map.size); + sg_res = NULL; + sg_map.virt = NULL; + printk(VENDOR ": probe failed\n"); + return -ENXIO; + } + + printk(KERN_NOTICE VENDOR ": %s device size = %dK\n", + sg_mtd->name, sg_mtd->size>>10); + + sg_mtd->owner = THIS_MODULE; + sg_mtd->priv = &sg_map; + register_reboot_notifier(&sg_notifier_block); + rc = add_mtd_partitions(sg_mtd, sg_partitions, NUM_PARTITIONS); + if (rc < 0) + printk(KERN_NOTICE VENDOR ": add_mtd_partitions() failed?\n"); + +#ifdef CONFIG_BLK_DEV_INITRD + if (phys_initrd_start == 0) +#endif + { + /* Mark mtd partition as root device */ + index = sg_getmtdindex(VENDOR " image"); + if (index >= 0) + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, index); + } + + return rc; +} + +/****************************************************************************/ + +void __exit sg_cleanup(void) +{ + unregister_reboot_notifier(&sg_notifier_block); + if (sg_mtd) { + del_mtd_partitions(sg_mtd); + map_destroy(sg_mtd); + } + if (sg_map.virt) { + iounmap(sg_map.virt); + sg_map.virt = NULL; + } + if (sg_res) { + release_mem_region(FLASH_ADDR, sg_map.size); + sg_res = NULL; + } +} + +/****************************************************************************/ + +module_init(sg_init); +module_exit(sg_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("SnapGear/ARM flash support"); + +/****************************************************************************/ diff --git a/drivers/mtd/maps/snapgear-uc.c b/drivers/mtd/maps/snapgear-uc.c new file mode 100644 index 00000000..f8a72924 --- /dev/null +++ b/drivers/mtd/maps/snapgear-uc.c @@ -0,0 +1,435 @@ +/****************************************************************************/ +/* + * Flash memory access on uClinux SnapGear like devices + * Copyright (C) 2001-2002, David McCullough + */ +/****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +/****************************************************************************/ + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +#define SIZE_128K (1 * 128 * 1024) +#define SIZE_1MB (1 * 1024 * 1024) +#define SIZE_2MB (2 * 1024 * 1024) +#define SIZE_4MB (4 * 1024 * 1024) +#define SIZE_8MB (8 * 1024 * 1024) +#define SIZE_16MB (16 * 1024 * 1024) + +#ifdef CONFIG_COLDFIRE +#define FLASH_BASE 0xf0000000 +#define BUS_WIDTH 2 +#endif + +#ifdef CONFIG_SUPERH +#define FLASH_BASE 0x00000000 +#define BUS_WIDTH 1 +#endif + +/****************************************************************************/ + +static struct map_info nettel_flash_map = { + .name = "Flash", +}; + +static struct map_info nettel_ram_map = { + .name = "RAM", +}; + +static struct mtd_info *ram_mtdinfo; +static struct mtd_info *flash_mtdinfo; + +/****************************************************************************/ + +static struct mtd_partition nettel_romfs[] = { + { .name = "Romfs" } +}; + +#define NUM_PARTITIONS (sizeof(nettel_romfs) / sizeof(nettel_romfs[0])) + +/****************************************************************************/ +/* + * The layout of our flash, note the order of the names, this + * means we use the same major/minor for the same purpose on all + * layouts (when possible) + */ + +static struct mtd_partition nettel_128k[] = { + { .name = "Bootloader", .offset = 0x00000000, .size = 0x00004000 }, + { .name = "Bootargs", .offset = 0x00004000, .size = 0x00004000 }, + { .name = "MAC", .offset = 0x00008000, .size = 0x00004000 }, + { .name = "Config", .offset = 0x00010000, .size = 0x00010000 }, + { .name = "Spare", .offset = 0x0000c000, .size = 0x00004000 }, + { .name = "Flash", .offset = 0 } +}; + +static struct mtd_partition nettel_1mb[] = { + { .name = "Bootloader", .offset = 0x00000000, .size = 0x00004000 }, + { .name = "Bootargs", .offset = 0x00004000, .size = 0x00002000 }, + { .name = "MAC", .offset = 0x00006000, .size = 0x00002000 }, + { .name = "Config", .offset = 0x000f0000, .size = 0x00010000 }, + { .name = "Spare", .offset = 0x00008000, .size = 0x00008000 }, + { .name = "Image", .offset = 0x00010000, .size = 0x000e0000 }, + { .name = "Flash", .offset = 0 } +}; + +static struct mtd_partition nettel_2mb[] = { + { .name = "Bootloader", .offset = 0x00000000, .size = 0x00004000 }, + { .name = "Bootargs", .offset = 0x00004000, .size = 0x00002000 }, + { .name = "MAC", .offset = 0x00006000, .size = 0x00002000 }, + { .name = "Config", .offset = 0x00010000, .size = 0x00010000 }, + { .name = "Spare", .offset = 0x00008000, .size = 0x00008000 }, + { .name = "Image", .offset = 0x00020000, .size = 0x001e0000 }, + { .name = "Flash", .offset = 0 } +}; + +#ifdef CONFIG_SH_SECUREEDGE5410 + +static struct mtd_partition nettel_4mb[] = { + { .name = "Boot data", .offset = 0x00000000, .size = 0x00020000 }, + { .name = "Config", .offset = 0x00020000, .size = 0x00040000 }, + { .name = "Image", .offset = 0x00060000, .size = 0x00000000 }, + { .name = "Flash", .offset = 0 } +}; + +static struct mtd_partition nettel_8mb[] = { + { .name = "Boot data", .offset = 0x00000000, .size = 0x00020000 }, + { .name = "Config", .offset = 0x00020000, .size = 0x00080000 }, + { .name = "Image", .offset = 0x000a0000, .size = 0x00000000 }, + { .name = "Flash", .offset = 0 } +}; + +#else + +static struct mtd_partition nettel_4mb[] = { + { .name = "Bootloader", .offset = 0x00000000, .size = 0x00004000 }, + { .name = "Bootargs", .offset = 0x00004000, .size = 0x00002000 }, + { .name = "MAC", .offset = 0x00006000, .size = 0x00002000 }, + { .name = "Config", .offset = 0x00010000, .size = 0x00010000 }, + { .name = "Spare", .offset = 0x00008000, .size = 0x00008000 }, + { .name = "Image", .offset = 0x00020000, .size = 0x001e0000 }, + { .name = "Flash", .offset = 0x00000000, .size = 0x00200000 }, + { .name = "Image2", .offset = 0x00220000, .size = 0x001e0000 }, + { .name = "Flash2", .offset = 0 } +}; + +static struct mtd_partition nettel_8mb[] = { + { .name = "Bootloader", .offset = 0x00000000, .size = 0x00020000 }, + { .name = "Bootargs", .offset = 0x00020000, .size = 0x00020000 }, + { .name = "MAC", .offset = 0x00040000, .size = 0x00020000 }, + { .name = "Config", .offset = 0x00080000, .size = 0x00080000 }, + { .name = "Spare", .offset = 0x00060000, .size = 0x00020000 }, + { .name = "Image", .offset = 0x00100000, .size = 0x00700000 }, + { .name = "Flash", .offset = 0 } +}; + +#endif + +static struct mtd_partition nettel_16mb[] = { + { .name = "Boot data", .offset = 0x00000000, .size = 0x00020000 }, + { .name = "Config", .offset = 0x00020000, .size = 0x00100000 }, + { .name = "Image", .offset = 0x00120000, .size = 0x00000000 }, + { .name = "Flash", .offset = 0 } +}; + +/****************************************************************************/ +/* + * Find the MTD device with the given name + */ + +static struct mtd_info *get_mtd_named(char *name) +{ + int i; + struct mtd_info *mtd; + + for (i = 0; i < MAX_MTD_DEVICES; i++) { + mtd = get_mtd_device(NULL, i); + if (mtd) { + if (strcmp(mtd->name, name) == 0) + return(mtd); + put_mtd_device(mtd); + } + } + return(NULL); +} + +/****************************************************************************/ +#ifdef CONFIG_MTD_CFI_INTELEXT +/* + * Set the Intel flash back to read mode as MTD may leave it in command mode + */ + +static int nettel_reboot_notifier( + struct notifier_block *nb, + unsigned long val, + void *v) +{ + struct cfi_private *cfi = nettel_flash_map.fldrv_priv; + int i; + + for (i = 0; cfi && i < cfi->numchips; i++) + cfi_send_gen_cmd(0xff, 0x55, cfi->chips[i].start, &nettel_flash_map, + cfi, cfi->device_type, NULL); + + return(NOTIFY_OK); +} + +static struct notifier_block nettel_notifier_block = { + nettel_reboot_notifier, NULL, 0 +}; + +#endif + +/****************************************************************************/ + +static int +nettel_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf) +{ + struct map_info *map = (struct map_info *) mtd->priv; + *mtdbuf = (u_char *) (map->map_priv_1 + (int)from); + *retlen = len; + return(0); +} + +/****************************************************************************/ + +static int __init +nettel_probe(int ram, unsigned long addr, int size, int buswidth) +{ + struct mtd_info *mymtd; + struct map_info *map_ptr; + + if (ram) + map_ptr = &nettel_ram_map; + else + map_ptr = &nettel_flash_map; + + map_ptr->bankwidth = buswidth; + map_ptr->map_priv_2 = addr; + map_ptr->phys = addr; + map_ptr->size = size; + + printk(KERN_NOTICE "SnapGear %s probe(0x%lx,%d,%d): %lx at %lx\n", + ram ? "ram" : "flash", + addr, size, buswidth, map_ptr->size, map_ptr->map_priv_2); + + map_ptr->virt = ioremap_nocache(map_ptr->map_priv_2, map_ptr->size); + + if (!map_ptr->virt) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + + simple_map_init(map_ptr); + if (!ram) { + mymtd = do_map_probe("cfi_probe", map_ptr); + if (!mymtd) + mymtd = do_map_probe("jedec_probe", map_ptr); + } else + mymtd = do_map_probe("map_ram", map_ptr); + + if (!mymtd) { + iounmap((void *)map_ptr->map_priv_1); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + mymtd->point = nettel_point; + mymtd->priv = map_ptr; + + if (ram) { + ram_mtdinfo = mymtd; + add_mtd_partitions(mymtd, nettel_romfs, NB_OF(nettel_romfs)); + return(0); + } + + flash_mtdinfo = mymtd; + switch (size) { + case SIZE_128K: + add_mtd_partitions(mymtd, nettel_128k, NB_OF(nettel_128k)); + break; + case SIZE_1MB: + add_mtd_partitions(mymtd, nettel_1mb, NB_OF(nettel_1mb)); + break; + case SIZE_2MB: + add_mtd_partitions(mymtd, nettel_2mb, NB_OF(nettel_2mb)); + break; + case SIZE_4MB: + add_mtd_partitions(mymtd, nettel_4mb, NB_OF(nettel_4mb)); + break; + case SIZE_8MB: + add_mtd_partitions(mymtd, nettel_8mb, NB_OF(nettel_8mb)); + break; + case SIZE_16MB: + add_mtd_partitions(mymtd, nettel_16mb, NB_OF(nettel_16mb)); + break; + } + + return 0; +} + +/****************************************************************************/ + +int __init nettel_mtd_init(void) +{ + int rc = -1; + struct mtd_info *mtd; +#ifdef CONFIG_COLDFIRE + extern char _ebss; +#endif + + /* + * I hate this ifdef stuff, but our HW doesn't always have + * the same chipsize as the map that we use + */ +#if defined(CONFIG_FLASH16MB) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_16MB, BUS_WIDTH); +#endif + +#if defined(CONFIG_FLASH8MB) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_8MB, BUS_WIDTH); +#endif + +#if defined(CONFIG_FLASH4MB) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_4MB, BUS_WIDTH); +#endif + +#if defined(CONFIG_FLASH2MB) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_2MB, BUS_WIDTH); +#endif + +#if defined(CONFIG_FLASH1MB) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_1MB, BUS_WIDTH); +#endif + +#if defined(CONFIG_FLASH128K) || defined(CONFIG_FLASHAUTO) + if (rc != 0) + rc = nettel_probe(0, FLASH_BASE, SIZE_128K, BUS_WIDTH); +#endif + +#ifdef CONFIG_COLDFIRE + /* + * Map in the filesystem from RAM last so that, if the filesystem + * is not in RAM for some reason we do not change the minor/major + * for the flash devices + */ +#ifndef CONFIG_ROMFS_FROM_ROM + if (0 != nettel_probe(1, (unsigned long) &_ebss, + PAGE_ALIGN(* (unsigned long *)((&_ebss) + 8)), 4)) + printk("Failed to probe RAM filesystem\n"); +#else + { + unsigned long start_area; + unsigned char *sp, *ep; + size_t len; + + start_area = (unsigned long) &_ebss; + + if (strncmp((char *) start_area, "-rom1fs-", 8) != 0) { + mtd = get_mtd_named("Image"); + if (mtd && mtd->point) { + if ((*mtd->point)(mtd, 0, mtd->size, &len, &sp) == 0) { + ep = sp + len; + while (sp < ep && strncmp(sp, "-rom1fs-", 8) != 0) + sp++; + if (sp < ep) + start_area = (unsigned long) sp; + } + } + if (mtd) + put_mtd_device(mtd); + } + if (0 != nettel_probe(1, start_area, + PAGE_ALIGN(* (unsigned long *)(start_area + 8)), 4)) + printk("Failed to probe RAM filesystem\n"); + } +#endif + + mtd = get_mtd_named("Romfs"); + if (mtd) { + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + put_mtd_device(mtd); + } else + printk("%s: Failed to find & make root filesystem\n", __FUNCTION__); +#endif + +#ifdef CONFIG_SH_SECUREEDGE5410 +#if defined(CONFIG_NFTL) || defined(CONFIG_INFTL) + ROOT_DEV = MKDEV(NFTL_MAJOR, 1); +#else + mtd = get_mtd_named("Image"); + if (mtd) { + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + put_mtd_device(mtd); + } +#endif +#endif + +#ifdef CONFIG_MTD_CFI_INTELEXT + register_reboot_notifier(&nettel_notifier_block); +#endif + + return(rc); +} + +/****************************************************************************/ + +static void __exit nettel_mtd_cleanup(void) +{ + if (flash_mtdinfo) { + del_mtd_partitions(flash_mtdinfo); + map_destroy(flash_mtdinfo); + flash_mtdinfo = NULL; + } + if (ram_mtdinfo) { + del_mtd_partitions(ram_mtdinfo); + map_destroy(ram_mtdinfo); + ram_mtdinfo = NULL; + } + if (nettel_ram_map.map_priv_1) { + iounmap((void *)nettel_ram_map.map_priv_1); + nettel_ram_map.map_priv_1 = 0; + } + if (nettel_flash_map.map_priv_1) { + iounmap((void *)nettel_flash_map.map_priv_1); + nettel_flash_map.map_priv_1 = 0; + } +} + +/****************************************************************************/ + +module_init(nettel_mtd_init); +module_exit(nettel_mtd_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support for uClinux"); + +/****************************************************************************/ diff --git a/drivers/mtd/maps/snapgeode.c b/drivers/mtd/maps/snapgeode.c new file mode 100644 index 00000000..bc8bb1ee --- /dev/null +++ b/drivers/mtd/maps/snapgeode.c @@ -0,0 +1,223 @@ +/****************************************************************************/ + +/* + * snapgeode.c -- mappings for SnapGear GEODE based boards + * + * (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2001-2003, SnapGear (www.snapgear.com) + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ + +static struct mtd_info *sg_mtd; + +/****************************************************************************/ +#ifdef CONFIG_MTD_CFI_INTELEXT +/****************************************************************************/ + +/* + * Intel FLASH setup. This is the only flash device, it is the entire + * non-volatile storage (no IDE CF or hard drive). + */ + +static struct map_info sg_map = { + .name= "SnapGear Intel/StrataFlash", + .phys= 0xff800000, + .size= 0x800000, + .buswidth= 1, +}; + +static struct mtd_partition sg_partitions[] = { + { + .name= "SnapGear kernel", + .offset= 0, + .size= 0x000e0000 + }, + { + .name= "SnapGear filesystem", + .offset= 0x00100000, + }, + { + .name= "SnapGear config", + .offset= 0x000e0000, + .size= 0x00020000 + }, + { + .name= "SnapGear Intel/StrataFlash", + .offset= 0 + }, + { + .name= "SnapGear BIOS Config", + .offset= 0x007e0000, + .size= 0x00020000 + }, + { + .name= "SnapGear BIOS", + .offset= 0x007e0000, + .size= 0x00020000 + }, +}; + +#define PROBE "cfi_probe" + +/****************************************************************************/ +#else +/****************************************************************************/ + +/* + * If only an AMD flash is fitted then it is the BIOS/boot loader. + * Primary non-volatile storage must be via some ither IDE mechanism + * (either compact flash [CF] or real hard drive). + */ + +static struct map_info sg_map = { + .name= "SnapGear AMD/Flash", + .phys= 0xff800000, + .size= 0x800000, + .buswidth= 1, +}; + +static struct mtd_partition sg_partitions[] = { + { + .name= "SnapGear BIOS config", + .offset= 0x000e0000, + .size= 0x00010000 + }, + { + .name= "SnapGear BIOS", + .offset= 0x000f0000, + .size= 0x00010000 + }, + { + .name= "SnapGear AMD/Flash", + .offset= 0 + }, +}; + +#define PROBE "jedec_probe" + +/****************************************************************************/ +#endif +/****************************************************************************/ + +#define NUM_PARTITIONS (sizeof(sg_partitions)/sizeof(sg_partitions[0])) + +/****************************************************************************/ + +#ifdef CONFIG_MTD_CFI_INTELEXT + +/* + * Set the Intel flash back to read mode. Sometimes MTD leaves the + * flash in status mode, and if you reboot there is no code to + * execute (the flash devices do not get a RESET) :-( + */ +static int sg_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v) +{ + struct cfi_private *cfi = sg_map.fldrv_priv; + unsigned long b; + + /* Make sure all FLASH chips are put back into read mode */ + for (b = 0; (b < sg_partitions[3].size); b += 0x100000) { + cfi_send_gen_cmd(0xff, 0x55, b, &sg_map, cfi, + cfi->device_type, NULL); + } + return NOTIFY_OK; +} + +static struct notifier_block sg_notifier_block = { + sg_reboot_notifier, NULL, 0 +}; + +#endif /* CONFIG_MTD_CFI_INTELEXT */ + +/****************************************************************************/ + +int __init sg_init(void) +{ + printk("SNAPGEAR: MTD BIOS setup\n"); + + /* + * On the GEODE the ROM CS stays mapped into high memory. + * So we look for it at the top of the 32bit address space. + */ + sg_map.virt = (unsigned long) ioremap(0xff800000, 0x800000); + if (sg_map.virt == 0) { + printk("SNAPGEAR: failed to ioremap() ROMCS\n"); + return -EIO; + } + + simple_map_init(&sg_map); + + if ((sg_mtd = do_map_probe(PROBE, &sg_map)) == NULL) + return -ENXIO; + + printk(KERN_NOTICE "SNAPGEAR: %s device size = %dK\n", + sg_mtd->name, sg_mtd->size>>10); + + sg_mtd->owner = THIS_MODULE; + sg_mtd->priv = &sg_map; + +#ifdef CONFIG_MTD_CFI_INTELEXT + sg_partitions[1].size = sg_mtd->size - + (sg_partitions[1].offset + sg_mtd->erasesize); + if (sg_mtd->size > 0x800000) { + sg_partitions[4].offset += sg_mtd->size - 0x800000; + sg_partitions[5].offset += sg_mtd->size - 0x800000; + } + register_reboot_notifier(&sg_notifier_block); +#ifndef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); +#endif +#else + if (sg_mtd->size > 0x100000) { + sg_partitions[0].offset += sg_mtd->size - 0x100000; + sg_partitions[1].offset += sg_mtd->size - 0x100000; + } +#endif /* !CONFIG_MTD_CFI_INTELEXT */ + + return add_mtd_partitions(sg_mtd, sg_partitions, NUM_PARTITIONS); +} + +/****************************************************************************/ + +void __exit sg_cleanup(void) +{ +#ifdef CONFIG_MTD_CFI_INTELEXT + unregister_reboot_notifier(&sg_notifier_block); +#endif + if (sg_mtd) { + del_mtd_partitions(sg_mtd); + map_destroy(sg_mtd); + } + if (sg_map.map_priv_1) { + iounmap((void *)sg_map.map_priv_1); + sg_map.map_priv_1 = 0; + } +} + +/****************************************************************************/ + +module_init(sg_init); +module_exit(sg_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("SnapGear/GEODE flash support"); + +/****************************************************************************/ diff --git a/drivers/mtd/maps/uc7101.c b/drivers/mtd/maps/uc7101.c new file mode 100644 index 00000000..b65eb2db --- /dev/null +++ b/drivers/mtd/maps/uc7101.c @@ -0,0 +1,102 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +#define UC7110_FLASH_SIZE 0x00400000 +#define WINDOW_SIZE UC7110_FLASH_SIZE + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x100000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x140000 /* root file system with JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "UC7101 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("victor.yu@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC7101-LX"); diff --git a/drivers/mtd/maps/uc7110.c b/drivers/mtd/maps/uc7110.c new file mode 100644 index 00000000..7a535a65 --- /dev/null +++ b/drivers/mtd/maps/uc7110.c @@ -0,0 +1,111 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +#define WINDOW_SIZE CONFIG_FLASH_SIZE +//#define WINDOW_SIZE 0x00800000 +//#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) + +#if (WINDOW_SIZE > 0x00800000 ) +#define RW_PART1_SZ 0x300000 /* Kernel */ +#define RW_PART2_SZ 0x400000 /* root file system use JFFS2 */ +#else +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_SZ (0x280000-RW_PART0_SZ) /* root file system use JFFS2 */ +#endif + +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +//#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk use JFFS2 */ +#define RW_PART3_SZ (WINDOW_SIZE-RW_PART3_OF) /* user disk use JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "UC7110LX V2 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7110-LX Version 2"); diff --git a/drivers/mtd/maps/uc7112.c b/drivers/mtd/maps/uc7112.c new file mode 100644 index 00000000..eb433450 --- /dev/null +++ b/drivers/mtd/maps/uc7112.c @@ -0,0 +1,102 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x280000 /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "UC7112 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7112"); diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 389fea28..428d1de0 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -24,19 +24,36 @@ /****************************************************************************/ -struct map_info uclinux_ram_map = { - .name = "RAM", +#ifdef CONFIG_MTD_UCLINUX_EBSS + #define MAP_TYPE "map_ram" + #define MAP_NAME "RAM" + #define CONFIG_MTD_UCLINUX_ADDRESS &_ebss + extern char _ebss; +#elif CONFIG_MTD_UCLINUX_RAM + #define MAP_TYPE "map_ram" + #define MAP_NAME "RAM" +#elif CONFIG_MTD_UCLINUX_ROM + #define MAP_TYPE "map_rom" + #define MAP_NAME "ROM" +#else + #error "Unknown uClinux map type" +#endif + +/****************************************************************************/ + +struct map_info uclinux_map = { + .name = MAP_NAME, }; -struct mtd_info *uclinux_ram_mtdinfo; +struct mtd_info *uclinux_mtdinfo; /****************************************************************************/ -struct mtd_partition uclinux_romfs[] = { +struct mtd_partition uclinux_fs[] = { { .name = "ROMfs" } }; -#define NUM_PARTITIONS ARRAY_SIZE(uclinux_romfs) +#define NUM_PARTITIONS ARRAY_SIZE(uclinux_fs) /****************************************************************************/ @@ -55,10 +72,9 @@ int __init uclinux_mtd_init(void) { struct mtd_info *mtd; struct map_info *mapp; - extern char _ebss; - unsigned long addr = (unsigned long) &_ebss; + unsigned long addr = (unsigned long) CONFIG_MTD_UCLINUX_ADDRESS; - mapp = &uclinux_ram_map; + mapp = &uclinux_map; mapp->phys = addr; mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(addr + 8)))); mapp->bankwidth = 4; @@ -75,7 +91,7 @@ int __init uclinux_mtd_init(void) simple_map_init(mapp); - mtd = do_map_probe("map_ram", mapp); + mtd = do_map_probe(MAP_TYPE, mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); iounmap(mapp->virt); @@ -86,11 +102,11 @@ int __init uclinux_mtd_init(void) mtd->point = uclinux_point; mtd->priv = mapp; - uclinux_ram_mtdinfo = mtd; - add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS); + uclinux_mtdinfo = mtd; + add_mtd_partitions(mtd, uclinux_fs, NUM_PARTITIONS); printk("uclinux[mtd]: set %s to be root filesystem\n", - uclinux_romfs[0].name); + uclinux_fs[0].name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); return(0); @@ -100,14 +116,14 @@ int __init uclinux_mtd_init(void) void __exit uclinux_mtd_cleanup(void) { - if (uclinux_ram_mtdinfo) { - del_mtd_partitions(uclinux_ram_mtdinfo); - map_destroy(uclinux_ram_mtdinfo); - uclinux_ram_mtdinfo = NULL; + if (uclinux_mtdinfo) { + del_mtd_partitions(uclinux_mtdinfo); + map_destroy(uclinux_mtdinfo); + uclinux_mtdinfo = NULL; } - if (uclinux_ram_map.virt) { - iounmap((void *) uclinux_ram_map.virt); - uclinux_ram_map.virt = 0; + if (uclinux_map.virt) { + iounmap((void *) uclinux_map.virt); + uclinux_map.virt = 0; } } diff --git a/drivers/mtd/maps/w311_test.c b/drivers/mtd/maps/w311_test.c new file mode 100644 index 00000000..321e719a --- /dev/null +++ b/drivers/mtd/maps/w311_test.c @@ -0,0 +1,102 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x280000 /* root file system with JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk with JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "W311 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7112"); diff --git a/drivers/mtd/maps/w315_ec.c b/drivers/mtd/maps/w315_ec.c new file mode 100644 index 00000000..6a0ea653 --- /dev/null +++ b/drivers/mtd/maps/w315_ec.c @@ -0,0 +1,102 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define UC7110_FLASH_SIZE 0x00800000 +#define WINDOW_ADDR 0x80000000 +#define WINDOW_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ 0x400000 /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "W315(EC)", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7112"); diff --git a/drivers/mtd/maps/w321_gl2.c b/drivers/mtd/maps/w321_gl2.c new file mode 100644 index 00000000..c9dc90df --- /dev/null +++ b/drivers/mtd/maps/w321_gl2.c @@ -0,0 +1,103 @@ +/* + * UC-7110-LX Version 2 Flash mapping driver + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define WINDOW_ADDR CONFIG_FLASH_MEM_BASE +//#define WINDOW_SIZE CONFIG_FLASH_SIZE +#define WINDOW_SIZE 0x00800000 +#define UC7110_FLASH_SIZE 0x00800000 + +#define RW_PART0_OF 0x0 +#define RW_PART0_SZ 0x40000 /* Bootloader */ +#define RW_PART1_OF (RW_PART0_OF+RW_PART0_SZ) +#define RW_PART1_SZ 0x200000 /* Kernel */ +#define RW_PART2_OF (RW_PART1_OF+RW_PART1_SZ) +#define RW_PART2_SZ (0x280000) /* root file system - JFFS2 */ +#define RW_PART3_OF (RW_PART2_OF+RW_PART2_SZ) +#define RW_PART3_SZ (UC7110_FLASH_SIZE-RW_PART3_OF) /* user disk - JFFS2 */ + +static struct mtd_partition moxart_flash_partitions[] = { + { + .name = "Bootloader", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "LinuxKernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "RootFileSystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + //.mask_flags = MTD_WRITEABLE + }, + { + .name = "UserDisk", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + } +}; +struct map_info moxart_flash_map = { + .name = "W321 FLASH", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = WINDOW_ADDR, + .virt = IO_ADDRESS(WINDOW_ADDR), +}; + + +#define NUM_MOXART_FLASH_PARTITIONS ARRAY_SIZE(moxart_flash_partitions) + +static struct mtd_info *moxart_mtd; + +int __init init_moxart_flash(void) +{ + printk(KERN_NOTICE "moxart: flash mapping: 0x%x at 0x%x\n", + WINDOW_SIZE, WINDOW_ADDR); + + simple_map_init(&moxart_flash_map); + + moxart_mtd = do_map_probe("cfi_probe",&moxart_flash_map); + + if (moxart_mtd) { + moxart_mtd->owner = THIS_MODULE; + return add_mtd_partitions(moxart_mtd, + moxart_flash_partitions, + NUM_MOXART_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_moxart_flash(void) +{ + if (moxart_mtd) { + del_mtd_partitions(moxart_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(moxart_mtd); + } +} + +module_init(init_moxart_flash); +module_exit(cleanup_moxart_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jimmy_chen@moxa.com.tw"); +MODULE_DESCRIPTION("MTD map driver for the UC-7110-LX Version 2"); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 178b53b5..75544a81 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -148,7 +148,11 @@ static int blktrans_open(struct inode *i, struct file *f) struct mtd_blktrans_ops *tr; int ret = -ENODEV; +#if 0 // mask by Victor Yu. 02-12-2007 dev = i->i_bdev->bd_disk->private_data; +#else + dev = i->u.i_bdev->bd_disk->private_data; +#endif tr = dev->tr; if (!try_module_get(dev->mtd->owner)) @@ -179,7 +183,11 @@ static int blktrans_release(struct inode *i, struct file *f) struct mtd_blktrans_ops *tr; int ret = 0; +#if 0 // mask by Victor Yu. 02-12-2007 dev = i->i_bdev->bd_disk->private_data; +#else + dev = i->u.i_bdev->bd_disk->private_data; +#endif tr = dev->tr; if (tr->release) @@ -206,7 +214,11 @@ static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) static int blktrans_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { +#if 0 // mask by Victor Yu. 02-12-2007 struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; +#else + struct mtd_blktrans_dev *dev = inode->u.i_bdev->bd_disk->private_data; +#endif struct mtd_blktrans_ops *tr = dev->tr; switch (cmd) { diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5b6acfcb..540d47b5 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -16,6 +16,7 @@ #include #include +#include #include static struct class *mtd_class; @@ -147,7 +148,7 @@ static int mtd_close(struct inode *inode, struct file *file) /* FIXME: This _really_ needs to die. In 2.5, we should lock the userspace buffer down and use it directly with readv/writev. */ -#define MAX_KMALLOC_SIZE 0x20000 +#define MAX_KMALLOC_SIZE 0x2000 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) { @@ -242,11 +243,14 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t return total_retlen; } /* mtd_read */ +#define WRITE_KBUF_SIZE MAX_KMALLOC_SIZE +static DECLARE_MUTEX(write_kbuf_sem); +static char *write_kbuf; + static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) { struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; - char *kbuf; size_t retlen; size_t total_retlen=0; int ret=0; @@ -263,23 +267,17 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count if (!count) return 0; - if (count > MAX_KMALLOC_SIZE) - kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); - else - kbuf=kmalloc(count, GFP_KERNEL); - - if (!kbuf) - return -ENOMEM; + down(&write_kbuf_sem); while (count) { - if (count > MAX_KMALLOC_SIZE) - len = MAX_KMALLOC_SIZE; + if (count > WRITE_KBUF_SIZE) + len = WRITE_KBUF_SIZE; else len = count; - if (copy_from_user(kbuf, buf, len)) { - kfree(kbuf); + if (copy_from_user(write_kbuf, buf, len)) { + up(&write_kbuf_sem); return -EFAULT; } @@ -292,7 +290,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ret = -EOPNOTSUPP; break; } - ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); + ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, write_kbuf); break; case MTD_MODE_RAW: @@ -300,7 +298,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count struct mtd_oob_ops ops; ops.mode = MTD_OOB_RAW; - ops.datbuf = kbuf; + ops.datbuf = write_kbuf; ops.oobbuf = NULL; ops.len = len; @@ -310,7 +308,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count } default: - ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); + ret = (*(mtd->write))(mtd, *ppos, len, &retlen, write_kbuf); } if (!ret) { *ppos += retlen; @@ -319,12 +317,12 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count buf += retlen; } else { - kfree(kbuf); + up(&write_kbuf_sem); return ret; } } - kfree(kbuf); + up(&write_kbuf_sem); return total_retlen; } /* mtd_write */ @@ -786,6 +784,17 @@ static int __init init_mtdchar(void) return PTR_ERR(mtd_class); } + /* Allocate write buffer. */ + down(&write_kbuf_sem); + write_kbuf = kmalloc(WRITE_KBUF_SIZE, GFP_KERNEL); + if (write_kbuf == NULL) { + up(&write_kbuf_sem); + class_destroy(mtd_class); + unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); + return -ENOMEM; + } + up(&write_kbuf_sem); + register_mtd_user(¬ifier); return 0; } diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1831340e..26578ba2 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -56,6 +56,13 @@ config MTD_NAND_SPIA depends on ARCH_P720T && MTD_NAND help If you had to ask, you don't have one. Say 'N'. + +config MTD_NAND_M5329 + tristate "NAND Flash device on M5329 board" + depends on M5329EVB && MTD_NAND + help + If you had to ask, you don't have one. Say 'N'. + config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index f7475935..e0f678f7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o +obj-$(CONFIG_MTD_NAND_M5329) += m5329.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 6107f532..5d1e1813 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -78,6 +78,9 @@ struct doc_priv { int curchip; int mh0_page; int mh1_page; + int setcol; + int activecol; + int page_addr; struct mtd_info *nextdoc; }; @@ -553,6 +556,191 @@ static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) return 0; } +static int doc2001plus_addroffset(struct mtd_info *mtd, int *columnp) +{ + if (*columnp >= 512) { + /* OOB area */ + *columnp -= 512; + return NAND_CMD_READOOB; + } + if (*columnp < 256) { + /* First 256 bytes --> READ0 */ + return NAND_CMD_READ0; + } + *columnp -= 256; + return NAND_CMD_READ1; +} + +/* + * Translate the given offset into the appropriate command and offset. + * This does the mapping using the 16bit interleave layout defined by + * M-Systems, and looks like this for a sector pair: + * +-----------+-------+-------+-------+--------------+---------+-----------+ + * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055| + * +-----------+-------+-------+-------+--------------+---------+-----+-----+ + * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB0| OOB1| + * +-----------+-------+-------+-------+--------------+---------+-----+-----+ + * Thing to remember is that 2 physical pages are interleaved together, and + * then mapped in the above odd looking way. + */ +static int doc2001plus_addroffset32(struct mtd_info *mtd, int command, int *columnp, int page_addr) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + int col = *columnp; + + if (command == NAND_CMD_READ1) + col += 256; + if (command == NAND_CMD_READOOB) + col += 512; + doc->setcol = col; + doc->activecol = col; + doc->page_addr = page_addr; + + /* Even numbered pages first. */ + if ((page_addr & 0x1) == 0) { + if (col < 512) { + *columnp = (col >> 1); + return NAND_CMD_READ0; + } + if (col < 520) { + *columnp = (col - 512) >> 1; + return NAND_CMD_READ1; + } + *columnp = ((col - 520) + 16) >> 1; + return NAND_CMD_READOOB; + } + + /* Odd number pages next */ + if (col < 502) { + *columnp = (col + 10) >> 1; + return NAND_CMD_READ1; + } + if (col < 518) { + *columnp = (col - 502) >> 1; + return NAND_CMD_READOOB; + } + if (col < 520) { + *columnp = ((col - 518) + 8) >> 1; + return NAND_CMD_READ1; + } + *columnp = ((col - 520) + 24) >> 1; + return NAND_CMD_READOOB; +} + +static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int readcmd = NAND_CMD_READ0; + + /* + * Must terminate write pipeline before sending any commands + * to the device. + */ + if (command == NAND_CMD_PAGEPROG) { + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + } + + /* + * Write out the command to the device. If using the interleaved + * device then we may need to map the command and address parts. + * Ick :-( + */ + switch (command) { + case NAND_CMD_SEQIN: + if (doc->ChipID == DOC_ChipID_DocMilPlus32) { + readcmd = doc2001plus_addroffset32(mtd, command, &column, page_addr); + page_addr >>= 1; + } else { + readcmd = doc2001plus_addroffset(mtd, &column); + } + WriteDOC(readcmd, docptr, Mplus_FlashCmd); + break; + case NAND_CMD_READ0: + case NAND_CMD_READ1: + case NAND_CMD_READOOB: + if (doc->ChipID == DOC_ChipID_DocMilPlus32) { + command = doc2001plus_addroffset32(mtd, command, &column, page_addr); + page_addr >>= 1; + } + break; + default: + break; + } + + WriteDOC(command, docptr, Mplus_FlashCmd); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + + if (column != -1 || page_addr != -1) { + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (this->options & NAND_BUSWIDTH_16) + column >>= 1; + WriteDOC(column, docptr, Mplus_FlashAddress); + } + if (page_addr != -1) { + WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress); + WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); + /* One more address cycle for higher density devices */ + if (this->chipsize & 0x0c000000) { + WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); + printk("high density\n"); + } + } + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + /* deassert ALE */ + if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID) + WriteDOC(0, docptr, Mplus_FlashControl); + } + + /* + * program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; + + case NAND_CMD_RESET: + if (this->dev_ready) + break; + udelay(this->chip_delay); + WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + while ( !(this->read_byte(mtd) & 0x40)); + return; + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!this->dev_ready) { + udelay (this->chip_delay); + return; + } + } + + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay (100); + /* wait until command is processed */ + while (!this->dev_ready(mtd)); +} + static u_char doc2001plus_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -568,19 +756,51 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) return ret; } +static int doc2001plus_maxlinesiz(struct doc_priv *doc) +{ + if (doc->ChipID == DOC_ChipID_DocMilPlus32) { + if (doc->activecol < (512+6)) + return (512+6 - doc->activecol); + if (doc->activecol < (512+8)) + return (512+8 - doc->activecol); + } + return (512+16 - doc->activecol); +} + static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; + void __iomem *docptr = doc->virtadr; + int i, want, siz, loop; - if (debug) - printk("writebuf of %d bytes: ", len); - for (i = 0; i < len; i++) { - WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); - if (debug && i < 16) - printk("%02x ", buf[i]); + for (loop = 0, want = len; ((loop < 3) && (want > 0)); loop++) { + if (debug)printk("writebuf of %d bytes: ", len); + + /* Figure out maximum strait line read size */ + siz = doc2001plus_maxlinesiz(doc); + if (siz > want) + siz = want; + + if (doc->setcol != doc->activecol) { + /* Finish existing write, and restart at new pos */ + doc2001plus_command(mtd, NAND_CMD_PAGEPROG, -1, -1); + doc200x_wait(mtd, this); + /* FIXME: handle failure cases */ + + doc2001plus_command(mtd, NAND_CMD_RESET, -1, -1); + doc2001plus_command(mtd, NAND_CMD_SEQIN, doc->activecol, doc->page_addr); + } + + for (i=0; i < len; i++) { + WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); + if (debug && i < 16) + printk("%02x ", buf[i]); + } + if (debug) printk("\n"); + + want -= siz; + doc->activecol += siz; } if (debug) printk("\n"); @@ -590,31 +810,45 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug) - printk("readbuf of %d bytes: ", len); - - /* Start read pipeline */ - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); + void __iomem *docptr = doc->virtadr; + u_char *nbuf = buf; + int i, want, siz, loop; + + for (loop = 0, want = len; ((loop < 3) && (want > 0)); loop++) { + if (debug)printk("readbuf of %d bytes: ", len); + + /* Figure out maximum strait line read size */ + siz = doc2001plus_maxlinesiz(doc); + if (siz > want) + siz = want; + + if (doc->setcol != doc->activecol) + doc2001plus_command(mtd, NAND_CMD_READ0, doc->activecol, doc->page_addr); + + /* Start read pipeline */ + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + for (i=0; i < siz-2; i++, nbuf++) { + *nbuf = ReadDOC(docptr, Mil_CDSN_IO); + if (debug && i < 16) + printk("%02x ", *nbuf); + } - for (i = 0; i < len - 2; i++) { - buf[i] = ReadDOC(docptr, Mil_CDSN_IO); + /* Terminate read pipeline */ + *nbuf = ReadDOC(docptr, Mplus_LastDataRead); if (debug && i < 16) - printk("%02x ", buf[i]); - } + printk("%02x ", *nbuf); + nbuf++; + *nbuf = ReadDOC(docptr, Mplus_LastDataRead); + if (debug && i < 16) + printk("%02x ", *nbuf); + nbuf++; + if (debug) printk("\n"); - /* Terminate read pipeline */ - buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead); - if (debug && i < 16) - printk("%02x ", buf[len - 2]); - buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead); - if (debug && i < 16) - printk("%02x ", buf[len - 1]); - if (debug) - printk("\n"); + want -= siz; + doc->activecol += siz; + } } static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) @@ -725,111 +959,6 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, } } -static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - /* - * Must terminate write pipeline before sending any commands - * to the device. - */ - if (command == NAND_CMD_PAGEPROG) { - WriteDOC(0x00, docptr, Mplus_WritePipeTerm); - WriteDOC(0x00, docptr, Mplus_WritePipeTerm); - } - - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->writesize) { - /* OOB area */ - column -= mtd->writesize; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - WriteDOC(readcmd, docptr, Mplus_FlashCmd); - } - WriteDOC(command, docptr, Mplus_FlashCmd); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - - if (column != -1 || page_addr != -1) { - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) - column >>= 1; - WriteDOC(column, docptr, Mplus_FlashAddress); - } - if (page_addr != -1) { - WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress); - WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) { - WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); - printk("high density\n"); - } - } - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - /* deassert ALE */ - if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || - command == NAND_CMD_READOOB || command == NAND_CMD_READID) - WriteDOC(0, docptr, Mplus_FlashControl); - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - udelay(this->chip_delay); - WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - while (!(this->read_byte(mtd) & 0x40)) ; - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay(this->chip_delay); - return; - } - } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)) ; -} - static int doc200x_dev_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -1392,7 +1521,11 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE; if (inftl_bbt_write) this->bbt_td->options |= NAND_BBT_WRITE; - this->bbt_td->pages[0] = 2; + if (doc->ChipID == DOC_ChipID_DocMilPlus32) { + mtd->erasesize <<= 1; + this->bbt_td->pages[0] = 4; + } else + this->bbt_td->pages[0] = 2; this->bbt_md = NULL; } else { this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION; @@ -1426,7 +1559,8 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) do without it for non-INFTL use, since all it gives us is autopartitioning, but I want to give it more thought. */ if (!numparts) - return -EIO; + numparts = nftl_partscan(mtd, parts); + if (!numparts) return -EIO; add_mtd_device(mtd); #ifdef CONFIG_MTD_PARTITIONS if (!no_autopart) @@ -1576,7 +1710,8 @@ static int __init doc_probe(unsigned long physadr) reg = DoC_Mplus_Toggle; break; case DOC_ChipID_DocMilPlus32: - printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); + reg = DoC_Mplus_Toggle; + break; default: ret = -ENODEV; goto notfound; @@ -1606,7 +1741,8 @@ static int __init doc_probe(unsigned long physadr) in fact the same DOC aliased to a new address. If writes to one chip's alias resolution register change the value on the other chip, they're the same chip. */ - if (ChipID == DOC_ChipID_DocMilPlus16) { + if ((ChipID == DOC_ChipID_DocMilPlus16) || + (ChipID == DOC_ChipID_DocMilPlus32)) { oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); newval = ReadDOC(virtadr, Mplus_AliasResolution); } else { @@ -1615,7 +1751,8 @@ static int __init doc_probe(unsigned long physadr) } if (oldval != newval) continue; - if (ChipID == DOC_ChipID_DocMilPlus16) { + if ((ChipID == DOC_ChipID_DocMilPlus16) || + (ChipID == DOC_ChipID_DocMilPlus32)) { WriteDOC(~newval, virtadr, Mplus_AliasResolution); oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it @@ -1678,7 +1815,8 @@ static int __init doc_probe(unsigned long physadr) if (ChipID == DOC_ChipID_Doc2k) numchips = doc2000_init(mtd); - else if (ChipID == DOC_ChipID_DocMilPlus16) + else if ((ChipID == DOC_ChipID_DocMilPlus16) || + (ChipID == DOC_ChipID_DocMilPlus32)) numchips = doc2001plus_init(mtd); else numchips = doc2001_init(mtd); diff --git a/drivers/mtd/nand/m5329.c b/drivers/mtd/nand/m5329.c new file mode 100644 index 00000000..4717c96d --- /dev/null +++ b/drivers/mtd/nand/m5329.c @@ -0,0 +1,179 @@ +/* + * drivers/mtd/nand/m5329.c + * + * Yaroslav Vinogradov (Yaroslav.Vinogradov@freescale.com) + * + * Copyright Freescale Semiconductor, Inc 2006 + * + * Using as template code from: + * drivers/mtd/nand/spia.c Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.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 or any later + * version (at your option) as published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * M5329EVB board which utilizes the Toshiba part. This is + * a 16MB NAND Flash device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MTD structure for M5329EVB board + */ +static struct mtd_info *m5329_mtd = NULL; + +/* + * Values specific to the SPIA board (used with EP7212 processor) + */ +#define NAND_FLASH_ADDRESS 0xd0000000 /* Fash address mapping */ + +#define CLE_ADDR_BIT 4 +#define ALE_ADDR_BIT 3 +#define NCE_ADDR_BIT 19 + +/* + * Module stuff + */ + +static unsigned int m5329_fio_base = NAND_FLASH_ADDRESS; + +module_param(m5329_fio_base, int, 0); + +/* + * Define partitions for flash device + */ +const static struct mtd_partition partition_info[] = { + { + .name = "M5329 flash partition 1", + .offset = 0, + .size = 16*1024*1024 + }, +}; +#define NUM_PARTITIONS 1 + + +/* + * hardware specific access to control-lines + */ +static void m5329_hwcontrol(struct mtd_info *mtd, int cmd){ + struct nand_chip *this; + unsigned int base; + + + /* Get pointer to private data */ + this = (struct nand_chip *) (&m5329_mtd[1]); + m5329_fio_base = (unsigned int)this->IO_ADDR_R; + base = m5329_fio_base; + + switch(cmd){ + case NAND_CTL_SETCLE: + m5329_fio_base |= 1<IO_ADDR_R = (void __iomem *) m5329_fio_base; + this->IO_ADDR_W = (void __iomem *) m5329_fio_base; +} + +/* + * Main initialization routine + */ +int __init m5329_init (void) +{ + struct nand_chip *this; + + /* Setup NAND flash chip select signals */ + MCF_FBCS2_CSAR = NAND_FLASH_ADDRESS; + MCF_FBCS2_CSCR = (MCF_FBCS_CSCR_PS_8 + | MCF_FBCS_CSCR_BEM + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_SBM + | MCF_FBCS_CSCR_WS(7)); + MCF_FBCS2_CSMR = (MCF_FBCS_CSMR_BAM_16M + | MCF_FBCS_CSMR_V); + + /* Allocate memory for MTD device structure and private data */ + m5329_mtd = kmalloc (sizeof(struct mtd_info)+sizeof (struct nand_chip), + GFP_KERNEL); + if (!m5329_mtd) { + printk ("Unable to allocate M5329 NAND MTD device structure\n"); + return -ENOMEM; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&m5329_mtd[1]); + + /* Initialize structures */ + memset((char *) m5329_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + m5329_mtd->priv = this; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = (void __iomem *) m5329_fio_base; + this->IO_ADDR_W = (void __iomem *) m5329_fio_base; + /* Set address of hardware control function */ + this->hwcontrol = m5329_hwcontrol; + /* 50 us command delay time */ + this->chip_delay = 50; + this->eccmode = NAND_ECC_SOFT; + + /* Scan to find existence of the device */ + if (nand_scan (m5329_mtd, 1)) { + kfree (m5329_mtd); + return -ENXIO; + } + + /* Register the partitions */ + add_mtd_partitions(m5329_mtd, partition_info, NUM_PARTITIONS); + + /* Return happy */ + return 0; +} +module_init(m5329_init); + +/* + * Clean up routine + */ +#ifdef MODULE +static void __exit m5329_cleanup (void) +{ + /* Release resources, unregister device */ + nand_release (m5329_mtd); + + /* Free the MTD device structure */ + kfree (m5329_mtd); +} +module_exit(m5329_cleanup); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yaroslav Vinogradov "); +MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on M5329 board"); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 458dd9f8..30be3192 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -70,19 +70,29 @@ #include #include #include +#ifdef CONFIG_LEDMAN +#include +#endif #include #include #include #include +/* do we want fast poll operation instead of interrupts */ +#ifdef CONFIG_FAST_TIMER +#define FAST_POLL 1 +#include +#endif + /* VLAN tagging feature enable/disable */ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define CP_VLAN_TAG_USED 1 -#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ - do { (tx_desc)->opts2 = (vlan_tag_value); } while (0) +#define CP_VLAN_TX_TAG(tx_desc, vlan_tag_value, do_vlan) \ + do { (tx_desc)->opts2 = (do_vlan ? cpu_to_le16(TxVlanTag) : 0); \ + tx_desc->vtag = cpu_to_be16(vlan_tag_value); } while (0) #else #define CP_VLAN_TAG_USED 0 -#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ +#define CP_VLAN_TX_TAG(tx_desc, vlan_tag_value, do_vlan) \ do { (tx_desc)->opts2 = 0; } while (0) #endif @@ -132,7 +142,10 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head : \ (CP)->tx_tail - (CP)->tx_head - 1) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +/* Used to calculate the size of the temporary rx buffer */ +#define CP_RX_FIFO_SZ 2048 +#define CP_RX_DMA_MARGIN 500 + #define RX_OFFSET 2 #define CP_INTERNAL_PHY 32 @@ -182,6 +195,7 @@ enum { TxThresh = 0xEC, /* Early Tx threshold */ OldRxBufAddr = 0x30, /* DMA address of Rx ring buffer (C mode) */ OldTSD0 = 0x10, /* DMA address of first Tx desc (C mode) */ + MIIRegister = 0xFC, /*The mii register */ /* Tx and Rx status descriptors */ DescOwn = (1 << 31), /* Descriptor is owned by NIC */ @@ -196,8 +210,8 @@ enum { IPCS = (1 << 18), /* Calculate IP checksum */ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ - TxVlanTag = (1 << 17), /* Add VLAN tag */ - RxVlanTagged = (1 << 16), /* Rx VLAN tag available */ + TxVlanTag = (1 << 1), /* Add VLAN tag */ + RxVlanTagged = (1 << 0), /* Rx VLAN tag available */ IPFail = (1 << 15), /* IP checksum failed */ UDPFail = (1 << 14), /* UDP/IP checksum failed */ TCPFail = (1 << 13), /* TCP/IP checksum failed */ @@ -299,6 +313,12 @@ enum { LANWake = (1 << 1), /* Enable LANWake signal */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ + /* mii register */ + MDO = (1 << 26), /* The mdio pin output */ + MDI = (1 << 25), /* the mdio pin input */ + MDC = (1 << 24), /* the mdio pin clock pin */ + MDM = (1 << 27), + cp_norx_intr_mask = PciErr | LinkChg | TxOK | TxErr | TxEmpty, cp_rx_intr_mask = RxOK | RxErr | RxEmpty | RxFIFOOvr, cp_intr_mask = cp_rx_intr_mask | cp_norx_intr_mask, @@ -310,7 +330,11 @@ static const unsigned int cp_rx_config = struct cp_desc { u32 opts1; - u32 opts2; +/* + * We break this filed into 2 16 bit fields to get around endiannes issues + */ + u16 vtag; + u16 opts2; u64 addr; }; @@ -402,6 +426,10 @@ static int cp_set_eeprom(struct net_device *dev, static struct pci_device_id cp_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), }, +#if defined(CONFIG_MTD_NETtel) || defined(CONFIG_SH_SECUREEDGE5410) + /* Bogus 8139 silicon reports 8129 without external PROM :-( */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8129), }, +#endif { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), }, { }, }; @@ -457,12 +485,21 @@ static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) static inline void cp_set_rxbufsize (struct cp_private *cp) { unsigned int mtu = cp->dev->mtu; - - if (mtu > ETH_DATA_LEN) - /* MTU + ethernet header + FCS + optional VLAN tag */ - cp->rx_buf_sz = mtu + ETH_HLEN + 8; + + /* + We need to ensure that the DMA buffers are bigger + than the rx fifo of the 8139C+, otherwise the DMA engine on + the chip can get confused and we cease to be able to receive + packets :-(. + + It seems to get confused if the size of the packet we are receiving + is the same size of as the DMA buffer. + */ + /* MTU + ethernet header + FCS + optional VLAN tag */ + if (mtu > (CP_RX_FIFO_SZ + CP_RX_DMA_MARGIN)) + cp->rx_buf_sz = mtu + ETH_HLEN + 8; else - cp->rx_buf_sz = PKT_BUF_SZ; + cp->rx_buf_sz = (CP_RX_FIFO_SZ + CP_RX_DMA_MARGIN); } static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, @@ -474,13 +511,22 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, cp->net_stats.rx_bytes += skb->len; cp->dev->last_rx = jiffies; +#ifdef FAST_POLL +#if CP_VLAN_TAG_USED + if (cp->vlgrp && (le16_to_cpu(desc->opts2) & RxVlanTagged)) { + vlan_hwaccel_rx(skb, cp->vlgrp, be16_to_cpu(desc->vtag)); + } else +#endif + netif_rx(skb); +#else /* FAST POLL */ #if CP_VLAN_TAG_USED - if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) { + if (cp->vlgrp && (le16_to_cpu(desc->opts2) & RxVlanTagged)) { vlan_hwaccel_receive_skb(skb, cp->vlgrp, - be16_to_cpu(desc->opts2 & 0xffff)); + be16_to_cpu(desc->vtag)); } else #endif netif_receive_skb(skb); +#endif /* FAST POLL */ } static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, @@ -516,16 +562,33 @@ static inline unsigned int cp_rx_csum_ok (u32 status) return 0; } +#ifdef FAST_POLL +static void cp_rx (struct cp_private *cp) +#else static int cp_rx_poll (struct net_device *dev, int *budget) +#endif { +#ifdef FAST_POLL + unsigned rx_work = 16; + struct net_device *dev = cp->dev; +#else struct cp_private *cp = netdev_priv(dev); - unsigned rx_tail = cp->rx_tail; unsigned rx_work = dev->quota; unsigned rx; +#endif + unsigned rx_tail = cp->rx_tail; + int cng_level = 0; + +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, (cp->dev->name[3] == '0') ? LEDMAN_LAN1_RX : + ((cp->dev->name[3] == '1') ? LEDMAN_LAN2_RX : LEDMAN_LAN3_RX)); +#endif +#ifndef FAST_POLL rx_status_loop: rx = 0; cpw16(IntrStatus, cp_rx_intr_mask); +#endif while (1) { u32 status, len; @@ -554,11 +617,13 @@ rx_status_loop: cp_rx_err_acct(cp, rx_tail, status, len); cp->net_stats.rx_dropped++; cp->cp_stats.rx_frags++; + cng_level = NET_RX_SUCCESS; goto rx_next; } if (status & (RxError | RxErrFIFO)) { cp_rx_err_acct(cp, rx_tail, status, len); + cng_level = NET_RX_SUCCESS; goto rx_next; } @@ -570,6 +635,7 @@ rx_status_loop: new_skb = dev_alloc_skb (buflen); if (!new_skb) { cp->net_stats.rx_dropped++; + cng_level = NET_RX_DROP; goto rx_next; } @@ -592,10 +658,13 @@ rx_status_loop: cp->rx_skb[rx_tail] = new_skb; cp_rx_skb(cp, skb, desc); +#ifndef FAST_POLL rx++; +#endif rx_next: cp->rx_ring[rx_tail].opts2 = 0; + cp->rx_ring[rx_tail].vtag = 0; cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping); if (rx_tail == (CP_RX_RING_SIZE - 1)) desc->opts1 = cpu_to_le32(DescOwn | RingEnd | @@ -604,12 +673,19 @@ rx_next: desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); rx_tail = NEXT_RX(rx_tail); + if (cng_level == NET_RX_DROP || cng_level == NET_RX_CN_HIGH + || cng_level == NET_RX_CN_MOD) { + rx_work = 0; + break; + } + if (!rx_work--) break; } cp->rx_tail = rx_tail; +#ifndef FAST_POLL dev->quota -= rx; *budget -= rx; @@ -629,6 +705,7 @@ rx_next: } return 1; /* not done */ +#endif } static irqreturn_t cp_interrupt (int irq, void *dev_instance) @@ -646,10 +723,15 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) return IRQ_NONE; if (netif_msg_intr(cp)) - printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n", - dev->name, status, cpr8(Cmd), cpr16(CpCmd)); + printk(KERN_DEBUG "%s: intr, status %04x cmd %02lx cpcmd %04lx\n", + dev->name, status, (unsigned long)cpr8(Cmd), + (unsigned long)cpr16(CpCmd)); +#ifdef FAST_POLL + cpw16_f(IntrStatus, status); +#else cpw16(IntrStatus, status & ~cp_rx_intr_mask); +#endif spin_lock(&cp->lock); @@ -661,10 +743,14 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) +#ifdef FAST_POLL + cp_rx(cp); +#else if (netif_rx_schedule_prep(dev)) { cpw16_f(IntrMask, cp_norx_intr_mask); __netif_rx_schedule(dev); } +#endif if (status & (TxOK | TxErr | TxEmpty | SWInt)) cp_tx(cp); @@ -700,11 +786,23 @@ static void cp_poll_controller(struct net_device *dev) } #endif +#ifdef FAST_POLL +static void fast_poll_8139cp(void *arg) +{ + cp_interrupt (-1, arg); +} +#endif + static void cp_tx (struct cp_private *cp) { unsigned tx_head = cp->tx_head; unsigned tx_tail = cp->tx_tail; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, (cp->dev->name[3] == '0') ? LEDMAN_LAN1_TX : + ((cp->dev->name[3] == '1') ? LEDMAN_LAN2_TX : LEDMAN_LAN3_TX)); +#endif + while (tx_tail != tx_head) { struct cp_desc *txd = cp->tx_ring + tx_tail; struct sk_buff *skb; @@ -764,6 +862,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) unsigned entry; u32 eor, flags; #if CP_VLAN_TAG_USED + int do_vlan = 0; u32 vlan_tag = 0; #endif int mss = 0; @@ -780,8 +879,10 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) } #if CP_VLAN_TAG_USED - if (cp->vlgrp && vlan_tx_tag_present(skb)) - vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb)); + if (cp->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + do_vlan = 1; + } #endif entry = cp->tx_head; @@ -796,7 +897,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) len = skb->len; mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); - CP_VLAN_TX_TAG(txd, vlan_tag); + CP_VLAN_TX_TAG(txd, vlan_tag, do_vlan); txd->addr = cpu_to_le64(mapping); wmb(); @@ -867,7 +968,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ctrl |= LastFrag; txd = &cp->tx_ring[entry]; - CP_VLAN_TX_TAG(txd, vlan_tag); + CP_VLAN_TX_TAG(txd, vlan_tag, do_vlan); txd->addr = cpu_to_le64(mapping); wmb(); @@ -879,7 +980,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) } txd = &cp->tx_ring[first_entry]; - CP_VLAN_TX_TAG(txd, vlan_tag); + CP_VLAN_TX_TAG(txd, vlan_tag, do_vlan); txd->addr = cpu_to_le64(first_mapping); wmb(); @@ -1063,7 +1164,9 @@ static void cp_init_hw (struct cp_private *cp) cpw16(MultiIntr, 0); +#ifndef FAST_POLL cpw16_f(IntrMask, cp_intr_mask); +#endif cpw8_f(Cfg9346, Cfg9346_Lock); } @@ -1088,6 +1191,7 @@ static int cp_refill_rx (struct cp_private *cp) cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; + cp->rx_ring[i].vtag = 0; cp->rx_ring[i].addr = cpu_to_le64(mapping); if (i == (CP_RX_RING_SIZE - 1)) cp->rx_ring[i].opts1 = @@ -1191,9 +1295,13 @@ static int cp_open (struct net_device *dev) cp_init_hw(cp); +#ifndef FAST_POLL rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev); if (rc) goto err_out_hw; +#else + fast_timer_add(fast_poll_8139cp, dev); +#endif netif_carrier_off(dev); mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE); @@ -1201,10 +1309,12 @@ static int cp_open (struct net_device *dev) return 0; +#ifndef FAST_POLL err_out_hw: cp_stop_hw(cp); cp_free_rings(cp); return rc; +#endif } static int cp_close (struct net_device *dev) @@ -1224,8 +1334,12 @@ static int cp_close (struct net_device *dev) spin_unlock_irqrestore(&cp->lock, flags); +#ifndef FAST_POLL synchronize_irq(dev->irq); free_irq(dev->irq, dev); +#else + fast_timer_remove(fast_poll_8139cp, dev); +#endif cp_free_rings(cp); return 0; @@ -1277,10 +1391,67 @@ static const char mii_2_8139_map[8] = { 0 }; + +#ifdef CONFIG_8139CP_EXTERNAL_PHY + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 25 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ +#define mdio_delay() cpr32(MIIRegister) + +#define MAX_PHYID (31) + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_cp_sync (struct cp_private *cp) { + int i; + + for (i = 32; i >= 0; i--) { + cpw32 (MIIRegister, MDO|MDM); + mdio_delay (); + cpw32 (MIIRegister, MDO | MDC | MDM); + mdio_delay (); + } +} +#endif + + static int mdio_read(struct net_device *dev, int phy_id, int location) { struct cp_private *cp = netdev_priv(dev); +#ifdef CONFIG_8139CP_EXTERNAL_PHY + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i; + int retval = 0; + + /* The CP can only use 32 external PHYs so try the internal */ + if (phy_id <= MAX_PHYID) { + mdio_cp_sync (cp); + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDO : 0; + + cpw32 (MIIRegister, dataval | MDM); + mdio_delay (); + cpw32 (MIIRegister, dataval | MDC | MDM); + mdio_delay (); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + cpw32 (MIIRegister, 0); + mdio_delay (); + retval = (retval << 1) | ((cpr32 (MIIRegister) & MDI) ? 1 : 0); + cpw32 (MIIRegister, MDC); + mdio_delay (); + } + return (retval >> 1) & 0xffff; + } +#endif + return location < 8 && mii_2_8139_map[location] ? readw(cp->regs + mii_2_8139_map[location]) : 0; } @@ -1290,7 +1461,32 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { struct cp_private *cp = netdev_priv(dev); +#ifdef CONFIG_8139CP_EXTERNAL_PHY + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int i; + /* If we select a valid internal phy */ + if (phy_id <= MAX_PHYID) { + mdio_cp_sync (cp); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = + (mii_cmd & (1 << i)) ? MDO : 0; + cpw32 (MIIRegister, dataval | MDM); + mdio_delay (); + cpw32 (MIIRegister, dataval | MDC | MDM); + mdio_delay (); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + cpw32 (MIIRegister, 0|MDM); + mdio_delay (); + cpw32 (MIIRegister, MDC|MDM); + mdio_delay (); + } + } else +#endif if (location == 0) { cpw8(Cfg9346, Cfg9346_Unlock); cpw16(BasicModeCtrl, value); @@ -1683,6 +1879,7 @@ static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len) return retval; } + static void write_eeprom(void __iomem *ioaddr, int location, u16 val, int addr_len) { @@ -1811,7 +2008,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; void __iomem *regs; resource_size_t pciaddr; - unsigned int addr_len, i, pci_using_dac; + unsigned int i, pci_using_dac; u8 pci_rev; #ifndef MODULE @@ -1823,7 +2020,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); if (pdev->vendor == PCI_VENDOR_ID_REALTEK && - pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) { + (pdev->device == PCI_DEVICE_ID_REALTEK_8139 || + pdev->device == PCI_DEVICE_ID_REALTEK_8129) + && pci_rev < 0x20) { dev_err(&pdev->dev, "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n", pdev->vendor, pdev->device, pci_rev); @@ -1846,7 +2045,11 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cp->mii_if.mdio_read = mdio_read; cp->mii_if.mdio_write = mdio_write; cp->mii_if.phy_id = CP_INTERNAL_PHY; +#ifdef CONFIG_8139CP_EXTERNAL_PHY + cp->mii_if.phy_id_mask = 0x3f; +#else cp->mii_if.phy_id_mask = 0x1f; +#endif cp->mii_if.reg_num_mask = 0x1f; cp_set_rxbufsize(cp); @@ -1914,11 +2117,20 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cp_stop_hw(cp); +#if defined(CONFIG_MTD_NETtel) || defined(CONFIG_SH_SECUREEDGE5410) || defined(CONFIG_MTD_SNAPGEODE) + /* Don't rely on the eeprom, get MAC from chip. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(regs + MAC0 + i); +#else +{ + unsigned int addr_len; /* read MAC address from EEPROM */ addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); +} +#endif memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; @@ -1927,11 +2139,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; +#ifndef FAST_POLL dev->poll = cp_rx_poll; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = cp_poll_controller; #endif dev->weight = 16; /* arbitrary? from NAPI_HOWTO.txt. */ +#endif #ifdef BROKEN dev->change_mtu = cp_change_mtu; #endif @@ -1975,6 +2189,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) /* enable busmastering and memory-write-invalidate */ pci_set_master(pdev); +#ifdef CONFIG_8139CP_EXTERNAL_PHY + { + /* Check if external phy exists. */ + int mii_status = mdio_read(dev, CONFIG_8139CP_PHY_NUM, 1); + if (mii_status != 0xffff && mii_status != 0x0000) + cp->mii_if.phy_id = CONFIG_8139CP_PHY_NUM; + } +#endif + if (cp->wol_enabled) cp_set_d3_state (cp); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d02ed51a..b2e2ed43 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -111,6 +111,10 @@ #include #include +#ifdef CONFIG_LEDMAN +#include +#endif + #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " @@ -258,7 +262,7 @@ static struct pci_device_id rtl8139_pci_tbl[] = { {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, -#ifdef CONFIG_SH_SECUREEDGE5410 +#if defined(CONFIG_MTD_NETtel) || defined(CONFIG_SH_SECUREEDGE5410) /* Bogus 8139 silicon reports 8129 without external PROM :-( */ {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, #endif @@ -970,10 +974,16 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, ioaddr = tp->mmio_addr; assert (ioaddr != NULL); +#if defined(CONFIG_MTD_NETtel) || defined(CONFIG_SH_SECUREEDGE5410) + /* Don't rely on the eeprom, get MAC from chip. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(ioaddr + MAC0 + i); +#else addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); +#endif memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ @@ -1710,6 +1720,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) unsigned int len = skb->len; unsigned long flags; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (dev->name[3] == '0') ? LEDMAN_LAN1_TX : LEDMAN_LAN2_TX); +#endif + /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; @@ -1974,6 +1989,11 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, } #endif +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, (dev->name[3] == '0') ? + LEDMAN_LAN1_RX : LEDMAN_LAN2_RX); +#endif + /* Packet copy from FIFO still in progress. * Theoretically, this should never happen * since EarlyRx is disabled. diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 3d1c599a..6a172a3e 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -41,6 +41,7 @@ module by all drivers that require it. Alan Cox : Spinlocking work, added 'BUG_83C690' Paul Gortmaker : Separate out Tx timeout code from Tx path. + Greg Ungerer : added some coldfire addressing code. Paul Gortmaker : Remove old unused single Tx buffer code. Hayato Fujiwara : Add m32r support. Paul Gortmaker : use skb_padto() instead of stack scratch area @@ -78,6 +79,18 @@ static const char version[] = #define NS8390_CORE #include "8390.h" +#ifdef CONFIG_COLDFIRE +#ifdef CONFIG_NE2K_PCI +#include +#else +#include +#endif /* CONFIG_NE2K_PCI */ +#endif /* CONFIG_COLDFIRE */ + +#ifdef CONFIG_LEDMAN +#include +#endif + #define BUG_83C690 /* These are the operational function interfaces to board-specific @@ -405,7 +418,11 @@ irqreturn_t ei_interrupt(int irq, void *dev_id) long e8390_base; int interrupts, nr_serviced = 0; struct ei_device *ei_local; - + +#ifdef CONFIG_M5272 + ne2000_irqack(irq); +#endif + e8390_base = dev->base_addr; ei_local = netdev_priv(dev); @@ -446,6 +463,19 @@ irqreturn_t ei_interrupt(int irq, void *dev_id) interrupts = 0; break; } +#ifdef CONFIG_LEDMAN + if (interrupts & (ENISR_TX|ENISR_TX_ERR)) { + ledman_cmd(LEDMAN_CMD_SET, + strcmp(dev->name, "eth0") == 0 ? + LEDMAN_LAN1_TX : + LEDMAN_LAN2_TX); + } else { + ledman_cmd(LEDMAN_CMD_SET, + strcmp(dev->name, "eth0") == 0 ? + LEDMAN_LAN1_RX : + LEDMAN_LAN2_RX); + } +#endif if (interrupts & ENISR_OVER) ei_rx_overrun(dev); else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) diff --git a/drivers/net/8390.h b/drivers/net/8390.h index f44f1220..ed7d53e3 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -28,6 +28,12 @@ extern int ei_debug; #define ei_debug 1 #endif +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c */ +extern void autoirq_setup(int waittime); +extern unsigned long autoirq_report(int waittime); +#endif + #ifdef CONFIG_NET_POLL_CONTROLLER extern void ei_poll(struct net_device *dev); #endif diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6e863aa9..a038da6d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -747,7 +747,7 @@ config LANCE config NET_VENDOR_SMC bool "Western Digital/SMC cards" - depends on NET_ETHERNET && (ISA || MCA || EISA || MAC) + depends on NET_ETHERNET && (ISA || MCA || EISA || MAC || EMBEDDED) help If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -837,7 +837,7 @@ config SMC91X config SMC9194 tristate "SMC 9194 support" - depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) + depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN || EMBEDDED) select CRC32 ---help--- This is support for the SMC9xxx based Ethernet cards. Choose this @@ -851,6 +851,18 @@ config SMC9194 . The module will be called smc9194. +config OPEN_ETH + bool "Opencores (Igor) Emac support" + help + This is support for the opencores Igor emac driver implemented + in an FPGA. + +config MTIP1000_ETH + bool "MoreThanIP 10_100_1000 Emac support" + help + This is support for the MoreThanIP 10_100_1000 emac driver implemented + in an FPGA. + config NET_NETX tristate "NetX Ethernet support" select MII @@ -874,6 +886,13 @@ config DM9000 . The module will be called dm9000. +config ETH_KS8695 + tristate "KS8695 ethernet support" + depends on ARCH_KS8695 + help + Say 'Y' here to enable support for the Kendin-Micrel KS8695 internal + ethernet ports. + config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 @@ -1103,7 +1122,7 @@ config ETH16I config NE2000 tristate "NE2000/NE1000 support" - depends on NET_ISA || (Q40 && m) || M32R + depends on NET_ISA || (Q40 && m) || M32R || EMBEDDED select CRC32 ---help--- If you have a network (Ethernet) card of this type, say Y and read @@ -1271,7 +1290,7 @@ config IBM_EMAC_TAH config NET_PCI bool "EISA, VLB, PCI and on board controllers" - depends on NET_ETHERNET && (ISA || EISA || PCI) + depends on NET_ETHERNET && (ISA || EISA || PCI || EMBEDDED) help This is another class of network cards which attach directly to the bus. If you have one of those, say Y and read the Ethernet-HOWTO, @@ -1444,7 +1463,7 @@ config FORCEDETH_NAPI config CS89x0 tristate "CS89x0 support" - depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X) + depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || M68328 || M68EZ328 || M68VZ328 || MACH_DM270) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -1456,6 +1475,14 @@ config CS89x0 . The module will be called cs89x0. +config CS89x0_SWAPPED + bool "Hardware swapped CS89x0" + depends on CS89x0 && !NET_PCI && !ISA + ---help--- + Say Y if your CS89x0 data bus is swapped. + This option is for single board computers using a CS89x0 chip. If you + are using a regular Ethernet card, say N. + config TC35815 tristate "TOSHIBA TC35815 Ethernet support" depends on NET_PCI && PCI && TOSHIBA_JMR3927 @@ -1611,6 +1638,19 @@ config 8139CP To compile this driver as a module, choose M here: the module will be called 8139cp. This is recommended. +config 8139CP_EXTERNAL_PHY + bool "External PHY support for the 8139C+ driver" + depends on 8139CP + help + Allows for an external PHY (ie., hub chip) + +config 8139CP_PHY_NUM + int "External PHY number for the 8139C+ driver" + depends on 8139CP_EXTERNAL_PHY + default "32" + help + The PHY number for the external PHY. + config 8139TOO tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support" depends on NET_PCI && PCI @@ -1862,16 +1902,9 @@ config DECLANCE DEC (now Compaq) based on the AMD Lance chipset, including the DEPCA series. (This chipset is better known via the NE2100 cards.) -config 68360_ENET - bool "Motorola 68360 ethernet controller" - depends on M68360 - help - Say Y here if you want to use the built-in ethernet controller of - the Motorola 68360 processor. - config FEC bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x + depends on M523x || M527x || M5272 || M528x || M520x || M532x help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire processors. diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f270bc49..af28a17f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -88,8 +88,9 @@ obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_SHAPER) += shaper.o obj-$(CONFIG_HP100) += hp100.o obj-$(CONFIG_SMC9194) += smc9194.o +obj-$(CONFIG_OPEN_ETH) += open_eth.o +obj-$(CONFIG_MTIP1000_ETH) += mtip1000.o obj-$(CONFIG_FEC) += fec.o -obj-$(CONFIG_68360_ENET) += 68360enet.o obj-$(CONFIG_ARM_ETHERH) += 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o obj-$(CONFIG_EL2) += 3c503.o 8390.o @@ -209,6 +210,7 @@ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/ +obj-$(CONFIG_ETH_KS8695) += ks8695/ obj-$(CONFIG_NETCONSOLE) += netconsole.o diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 678e4f48..d3dbcab4 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -24,6 +24,13 @@ config ARM_ETHER3 If you have an Acorn system with one of these network cards, you should say Y to this option if you wish to use it with Linux. +config MOXA_NET + bool "Moxa network driver" + depends on ARCH_MOXART && NET_ETHERNET + help + The moxa network devices driver was recently maintain by + Victor_yu@moxa.com.tw. + config ARM_ETHERH tristate "I-cubed EtherH/ANT EtherM support" depends on NET_ETHERNET && ARM && ARCH_ACORN @@ -46,3 +53,30 @@ config EP93XX_ETH help This is a driver for the ethernet hardware included in EP93xx CPUs. Say Y if you are building a kernel for EP93xx based devices. + +config ARM_ETHER00 + tristate "Altera Ether00 support" + depends on NET_ETHERNET && ARM && ARCH_CAMELOT + help + This is the driver for Altera's ether00 ethernet mac IP core. Say + Y here if you want to build support for this into the kernel. It + is also available as a module (say M here) that can be inserted/ + removed from the kernel at the same time as the PLD is configured. + If this driver is running on an epxa10 development board then it + will generate a suitable hw address based on the board serial + number (MTD support is required for this). Otherwise you will + need to set a suitable hw address using ifconfig. + +config ETH_S3C4510B + bool "Samsung S3C4510B Ethernet Support" + depends on NET_ETHERNET && ARM && CPU_S3C4510B + help + This is the driver for Samsung's S3C4510B SoC MAC IP core. Say + Y here if you want to build support for this into the kernel. + +config P2001_ETH + tristate "P2001 ethernet driver" + depends on NET_ETHERNET && ARM && MII && ARCH_P2001 + default y + help + P2001 ethernet driver diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index a4c86827..d564b795 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -9,3 +9,6 @@ obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o +obj-$(CONFIG_ETH_S3C4510B) += eth_s3c4510b.o +obj-$(CONFIG_P2001_ETH) += p2001_eth.o +obj-$(CONFIG_MOXA_NET) += eth_moxa.o diff --git a/drivers/net/arm/eth_moxa.c b/drivers/net/arm/eth_moxa.c new file mode 100644 index 00000000..20c6e424 --- /dev/null +++ b/drivers/net/arm/eth_moxa.c @@ -0,0 +1,904 @@ + +/* + * This program is the Moxa CPU ethernet device driver. + * + * History: + * Date Author Comment + * 06-15-2005 Victor Yu. Create it. Make it for Faraday demo board. + * 11-04-2005 Victor Yu. Modify it to support Moxa CPU demo board. + * 02-09-2007 Victor Yu. Porting to kernel 2.6.19. + */ +#if 1 // add by Victor Yu. 02-09-2007 +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "eth_moxa.h" + +//#define MCPU_MAC_DEBUG + +//#define USE_SCHEDULE_WORK +/* Jimmy_chen@moxa.com.tw: get mac from flash */ +#define ETH1_OFFSET 0x50 +#define ETH2_OFFSET 0x56 + +#ifdef MCPU_MAC_DEBUG +#define dbg_printk(x...) printk(x) +#else // MCPU_MAC_DEBUG +#define dbg_printk(x...) +#endif // MCPU_MAC_DEBUG + +#define TX_DESC_NUM 64 +#define TX_DESC_NUM_MASK (TX_DESC_NUM-1) +#define RX_DESC_NUM 64 +#define RX_DESC_NUM_MASK (RX_DESC_NUM-1) +#define TX_BUF_SIZE 1600 +#define RX_BUF_SIZE 1600 +#if TX_BUF_SIZE >= TXBUF_SIZE_MAX +#error Moxa CPU ethernet device driver Tx buffer size too large ! +#endif +#if RX_BUF_SIZE >= RXBUF_SIZE_MAX +#error Moxa CPU ethernet device driver Rx buffer size too large ! +#endif + +static mcpu_mac_priv_t mcpu_mac_priv; +#ifdef CONFIG_ARCH_MOXART + #if !defined(CONFIG_ARCH_W325_EC) && !defined(CONFIG_ARCH_EM1220_APIT) +static mcpu_mac_priv_t mcpu_mac_priv2; + #endif +#endif // CONFIG_ARCH_MOXART + +#ifdef HAVE_MULTICAST +static int crc32( char * s, int length ) +{ + /* indices */ + int perByte; + int perBit; + /* crc polynomial for Ethernet */ + const unsigned long poly=0xedb88320; + /* crc value - preinitialized to all 1's */ + unsigned long crc_value=0xffffffff; + + for ( perByte = 0; perByte < length; perByte ++ ) { + unsigned char c; + + c = *(s++); + for ( perBit = 0; perBit < 8; perBit++ ) { + crc_value = (crc_value>>1)^ + (((crc_value^c)&0x01)?poly:0); + c >>= 1; + } + } + return crc_value; +} + +static void mcpu_mac_setmulticast(unsigned int ioaddr, int count, struct dev_mc_list * addrs ) +{ + struct dev_mc_list *cur_addr; + int crc_val; + + for (cur_addr = addrs ; cur_addr!=NULL ; cur_addr = cur_addr->next ) { + if ( !( *cur_addr->dmi_addr & 1 ) ) + continue; + crc_val = crc32( cur_addr->dmi_addr, 6 ); + crc_val = (crc_val>>26)&0x3f; // ¨ú MSB 6 bit + if (crc_val >= 32) + outl(inl(ioaddr+MATH1_REG_OFFSET) | (1UL<<(crc_val-32)), ioaddr+MATH1_REG_OFFSET); + else + outl(inl(ioaddr+MATH0_REG_OFFSET) | (1UL<priv; + unsigned long flags; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#ifdef USE_SCHEDULE_WORK + spin_lock(&priv->rxlock); +#endif + spin_lock(&priv->txlock); + + if ( dev->flags & IFF_PROMISC ) + priv->maccr |= RCV_ALL; + else + priv->maccr &= ~RCV_ALL; + + if ( dev->flags & IFF_ALLMULTI ) + priv->maccr |= RX_MULTIPKT; + else + priv->maccr &= ~RX_MULTIPKT; + + if ( dev->mc_count ) { + priv->maccr |= HT_MULTI_EN; + mcpu_mac_setmulticast(dev->base_addr, dev->mc_count, dev->mc_list); + } else + priv->maccr &= ~HT_MULTI_EN; + + outl(priv->maccr, dev->base_addr+MACCR_REG_OFFSET); + + spin_unlock(&priv->txlock); +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE +} +#endif // HAVE_MULTICAST + +#if 1 // add by Victor Yu. 07-04-2005 +static void mywordcopy(void *dest, void *source, int len) +{ + unsigned short *pd=(unsigned short *)dest; + unsigned short *ps=(unsigned short *)source; + int wlen=len>>1; + + while ( wlen > 0 ) { + *pd++=*ps++; + wlen--; + } + if ( len & 1 ) + *(unsigned char *)pd = *(unsigned char *)ps; +} +#endif // 07-04-2005 + +static void mcpu_mac_recv(void *ptr) +{ + struct net_device *dev=(struct net_device *)ptr; + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + rx_desc_t *rxdesc; + int len; + struct sk_buff *skb; + unsigned char *data; +#if 1 // add by Victor Yu. 07-04-2005 + unsigned int ui; + int rxnow=priv->RxDescNow; +#endif // 07-04-2005 +#ifndef USE_SCHEDULE_WORK + int loops=RX_DESC_NUM; +#endif // USE_SCHEDULE_WORK + + dbg_printk("mcpu_mac_recv test01\n"); +#if 0 + dbg_printk("RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", priv->RxDescNow, priv->phyRxDescBaseAddr+(priv->RxDescNow*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[priv->RxDescNow], priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes2.virtRxBufBaseAddr); + dbg_printk("Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes0.ui, priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes1.ui); +#endif +#ifdef USE_SCHEDULE_WORK + spin_lock(&priv->rxlock); +#endif // USE_SCHEDULE_WORK +repeat_recv: + rxdesc = &priv->virtRxDescBaseAddr[rxnow]; +#if 0 // mask by Victor Yu. 07-04-2005 + if ( rxdesc->rxdes0.ubit.RxDMAOwn ) { +#else // add by Victor Yu. 07-04-2005 + ui = rxdesc->rxdes0.ui; + if ( ui & RXDMA_OWN ) { +#endif // 07-04-2005 +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#else +#ifdef MCPU_MAC_DEBUG + if ( loops == RX_DESC_NUM ) + printk("Bad receive packet !\n"); +#endif // MCPU_MAC_DEBUG +#endif // USE_SCHEDULE_WORK + return; + } +#if 0 // mask by Victor Yu. 07-04-2005 + if ( rxdesc->rxdes0.ubit.RxErr || + rxdesc->rxdes0.ubit.CRCErr || + rxdesc->rxdes0.ubit.Ftl || + rxdesc->rxdes0.ubit.Runt || + rxdesc->rxdes0.ubit.RxOddNb ) { +#else // add by Victor Yu. 07-04-2005 + if ( ui & (RX_ERR|CRC_ERR|FTL|RUNT|RX_ODD_NB) ) { +#endif // 07-04-2005 + dbg_printk("Ethernet receive packet error !\n"); + priv->stats.rx_dropped++; + priv->stats.rx_errors++; + goto recv_finish; + } +#if 0 // mask by Victor Yu. 07-04-2005 + len = rxdesc->rxdes0.ubit.RecvFrameLen > RX_BUF_SIZE ? RX_BUF_SIZE : rxdesc->rxdes0.ubit.RecvFrameLen; +#else // add by Victor Yu. 07-04-2005 + len = ui & RFL_MASK; + if ( len > RX_BUF_SIZE ) + len = RX_BUF_SIZE; +#endif // 07-04-2005 + skb = dev_alloc_skb(len+2); + if ( skb == NULL ) { + dbg_printk("Allocate memory fail !\n"); + priv->stats.rx_dropped++; + goto recv_finish; + } + skb_reserve(skb, 2); + skb->dev = dev; + data = skb_put(skb, len); + dbg_printk("receive data pointer = 0x%x\n", (unsigned long)data); +#if 0 // mask by Victor Yu. 07-04-2005 + memcpy(data, rxdesc->rxdes2.virtRxBufBaseAddr, len); +#else // add by Victor Yu. 07-04-2005 + mywordcopy((void *)data, (void *)rxdesc->rxdes2.virtRxBufBaseAddr, len); +#endif // 07-04-2005 + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + /* Jimmy_chen@moxa.com.tw :This is need by bonding driver to replace miion */ + dev->last_rx = jiffies ; + priv->stats.rx_packets++; + priv->stats.rx_bytes += len; + if ( ui & MULTICAST_RXDES0 ) + priv->stats.multicast++; + dbg_printk("Receive a good packet.\n"); + +recv_finish: +#if 0 // mask by Victor Yu. 07-04-2005 + rxdesc->rxdes0.ui = 0; + rxdesc->rxdes0.ubit.RxDMAOwn = 1; + rxdesc->rxdes1.ubit.RxBufSize = RX_BUF_SIZE; +#else // add by Victor Yu. 07-04-2005 + rxdesc->rxdes0.ui = RXDMA_OWN; +#endif // 07-04-2005 + rxnow++; + rxnow &= RX_DESC_NUM_MASK; + priv->RxDescNow = rxnow; + +#ifdef USE_SCHEDULE_WORK + goto repeat_recv; +#else // USE_SCHEDULE_WORK + if ( loops-- > 0 ) + goto repeat_recv; +#endif // USE_SCHEDULE_WORK + +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#endif // USE_SCHEDULE_WORK +} + +static void mcpu_mac_free_memory(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + + if ( priv->virtTxDescBaseAddr ) { + kfree(priv->virtTxDescBaseAddr); + priv->virtTxDescBaseAddr = NULL; + } + if ( priv->virtRxDescBaseAddr ) { + kfree(priv->virtRxDescBaseAddr); + priv->virtRxDescBaseAddr = NULL; + } + if ( priv->virtTxBufBaseAddr ) { + kfree(priv->virtTxBufBaseAddr); + priv->virtTxBufBaseAddr = NULL; + } + if ( priv->virtRxBufBaseAddr ) { + kfree(priv->virtRxBufBaseAddr); + priv->virtRxBufBaseAddr = NULL; + } +} + +static void mcpu_mac_setup_desc_ring(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + int i; + tx_desc_t *txdesc; + rx_desc_t *rxdesc; + unsigned char *virtbuf; + unsigned int phybuf; + + virtbuf = priv->virtTxBufBaseAddr; + phybuf = priv->phyTxBufBaseAddr; + for ( i=0; ivirtTxDescBaseAddr[i]; + memset(txdesc, 0, sizeof(tx_desc_t)); + txdesc->txdes2.phyTxBufBaseAddr = phybuf; + txdesc->txdes2.virtTxBufBaseAddr = virtbuf; + } + priv->virtTxDescBaseAddr[TX_DESC_NUM-1].txdes1.ubit.Edotr = 1; + + virtbuf = priv->virtRxBufBaseAddr; + phybuf = priv->phyRxBufBaseAddr; + for ( i=0; ivirtRxDescBaseAddr[i]; + memset(rxdesc, 0, sizeof(rx_desc_t)); + rxdesc->rxdes0.ubit.RxDMAOwn = 1; + rxdesc->rxdes1.ubit.RxBufSize = RX_BUF_SIZE; + rxdesc->rxdes2.phyRxBufBaseAddr = phybuf; + rxdesc->rxdes2.virtRxBufBaseAddr = virtbuf; + } + priv->virtRxDescBaseAddr[RX_DESC_NUM-1].rxdes1.ubit.Edorr = 1; + //dbg_printk("First Rx desc des0=0x%x, des1=%x\n", priv->virtRxDescBaseAddr[0].rxdes0.ui, priv->virtRxDescBaseAddr[0].rxdes1.ui); + + priv->TxDescNow = priv->RxDescNow = 0; + + // reset the MAC controler Tx/Rx desciptor base address + outl(priv->phyTxDescBaseAddr, dev->base_addr+TXR_BADR_REG_OFFSET); + outl(priv->phyRxDescBaseAddr, dev->base_addr+RXR_BADR_REG_OFFSET); +#if 0 + dbg_printk("Tx/Rx desc phy=0x%x,0x%x, virt=0x%x,0x%x\n", priv->phyTxDescBaseAddr, priv->phyRxDescBaseAddr, (unsigned int)priv->virtTxDescBaseAddr, (unsigned int)priv->virtRxDescBaseAddr); + dbg_printk("set Tx desc base address=0x%x, Rx=0x%x\n", inl(dev->base_addr+TXR_BADR_REG_OFFSET), inl(dev->base_addr+RXR_BADR_REG_OFFSET)); +#endif +} + +static void mcpu_mac_reset(struct net_device *dev) +{ + unsigned int reg=dev->base_addr+MACCR_REG_OFFSET; + + outl(SW_RST, reg); // software reset + while ( inl(reg) & SW_RST ) mdelay(10); + // maybe we need to disable the all interrupt + outl(0, dev->base_addr+IMR_REG_OFFSET); +#if 0 // mask by Victor Yu. 02-09-2007 + ((mcpu_mac_priv_t *)dev->priv)->maccr = RX_BROADPKT | FULLDUP | CRC_APD; +#else // to support 10M hub + ((mcpu_mac_priv_t *)dev->priv)->maccr = RX_BROADPKT | FULLDUP | CRC_APD | ENRX_IN_HALFTX; +#endif +} + +static void mcpu_mac_set_mac_address(unsigned int base, unsigned char *macaddr) +{ + unsigned int val; + + val = (((u32)macaddr[0] << 8) &0xff00) | ((u32)macaddr[1] & 0xff); + outl(val, base); + val = (((u32)macaddr[2]<<24) & 0xff000000) | + (((u32)macaddr[3]<<16) & 0x00ff0000) | + (((u32)macaddr[4]<<8) & 0x0000ff00) | + (((u32)macaddr[5]) & 0x000000ff); + outl(val, base+4); +} + +#ifdef MCPU_MAC_DEBUG // add by Victor Yu. 03-14-2006 +static void mcpu_mac_get_mac_address(unsigned int base, unsigned char *macaddr) +{ + unsigned int val; + + val = inl(base); + macaddr[0] = (val >> 8) & 0xff; + macaddr[1] = val & 0xff; + val = inl(base+4); + macaddr[2] = (val >> 24) & 0xff; + macaddr[3] = (val >> 16) & 0xff; + macaddr[4] = (val >> 8) & 0xff; + macaddr[5] = val & 0xff; +} +#endif + +static void mcpu_mac_enable(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + unsigned int base=dev->base_addr; + + outl(0x00001010, base+ITC_REG_OFFSET); + outl(0x00000001, base+APTC_REG_OFFSET); + outl(0x00000390, base+DBLAC_REG_OFFSET); +#ifdef MCPU_MAC_DEBUG + outl(RPKT_FINISH_M|NORXBUF_M|AHB_ERR_M, base+IMR_REG_OFFSET); +#else + outl(RPKT_FINISH_M, base+IMR_REG_OFFSET); +#endif + priv->maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN); + outl(priv->maccr, base+MACCR_REG_OFFSET); +} + +static void mcpu_mac_tx_timeout(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + unsigned long flags; + + dbg_printk("mcpu_mac_tx_timeout test01\n"); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#ifdef USE_SCHEDULE_WORK + spin_lock(&priv->rxlock); +#endif + spin_lock(&priv->txlock); + mcpu_mac_reset(dev); + mcpu_mac_set_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, dev->dev_addr); + mcpu_mac_setup_desc_ring(dev); + mcpu_mac_enable(dev); + spin_unlock(&priv->txlock); +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + netif_wake_queue(dev); + dev->trans_start = jiffies; +} + +#include +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) +{ + static u32 ethcmd; + static struct ethtool_value edata = {ETHTOOL_GLINK}; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GLINK: { + u32 phycrw_value = 0 ; + u16 phycrr_value = 0 ; + + /* Jimmy_chen@moxa.com.tw : RTL8201CP 15 pages */ + /* Here is bug not fix yet, why i need do twice? */ + phycrw_value = (1<<16)|((PHY_STATUS_REG&0x1f)<<21)|FTMAC100_REG_PHY_READ ; + outl(phycrw_value,dev->base_addr+PHYCR_REG_OFFSET) ; + udelay(10) ; + phycrr_value = inw(dev->base_addr+PHYCR_REG_OFFSET); + printk("ETHTOOL_GLINK 0x%x-",phycrr_value) ; + + phycrw_value = (1<<16)|((PHY_STATUS_REG&0x1f)<<21)|FTMAC100_REG_PHY_READ ; + outl(phycrw_value,dev->base_addr+PHYCR_REG_OFFSET) ; + udelay(10) ; + phycrr_value = inw(dev->base_addr+PHYCR_REG_OFFSET); + printk("0x%x\n",phycrr_value) ; + /* Jimmy_chen@moxa.com.tw : emulate mii_link_ok function */ + if((phycrr_value&Link_Status)==Link_Status) + edata.data = 1 ; + else + edata.data = 0 ; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + default: + return -EOPNOTSUPP; + } +} +static int mcpu_mac_iotcl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)rq; + + switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, rq->ifr_data); + /* + value = (1<<16)|(PHY_STATUS_REG&0x1f<<21)|FTMAC100_REG_PHY_READ ; + outl(value,dev->base_addr+PHYCR_REG_OFFSET) ; + udelay(10) ; + value = inl(dev->base_addr+PHYCR_REG_OFFSET); + return 0 ; + */ + default: + return -EOPNOTSUPP; + } +} +static int mcpu_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + tx_desc_t *txdesc; + int len; + int txnow=priv->TxDescNow; + + dbg_printk("mcpu_mac_hard_start_xmit test01\n"); + spin_lock(&priv->txlock); + + // first check the Tx buffer is enough or not + txdesc = &priv->virtTxDescBaseAddr[txnow]; + if ( txdesc->txdes0.ubit.TxDMAOwn ) { + dbg_printk("No Tx space to transmit the packet !\n"); + priv->stats.tx_dropped++; + goto xmit_final; + } + + // fill the data +#if 0 // mask by Victor Yu. 07-04-2005 + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + len = len > TX_BUF_SIZE ? TX_BUF_SIZE : len; +#else // add by Victor Yu. 07-04-2005 + len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len; +#endif +#if 0 // mask by Victor Yu. 07-04-2005 + memcpy(txdesc->txdes2.virtTxBufBaseAddr, skb->data, len); +#else // add by Victor Yu. 07-04-2005 + mywordcopy((void *)txdesc->txdes2.virtTxBufBaseAddr, (void *)skb->data, len); +#endif + dbg_printk("transmit data pointer = 0x%x\n", (unsigned long)skb->data); +#if 1 // add by Victor Yu. 07-04-2005 + if ( skb->len < ETH_ZLEN ) { + memset(&txdesc->txdes2.virtTxBufBaseAddr[skb->len], 0, ETH_ZLEN-skb->len); + len = ETH_ZLEN; + } +#endif + txdesc->txdes1.ubit.Lts = 1; + txdesc->txdes1.ubit.Fts = 1; + txdesc->txdes1.ubit.Tx2fic = 0; + txdesc->txdes1.ubit.Txic = 0; + txdesc->txdes1.ubit.TxBufSize = len; +#if 0 // mask by Victor Yu. 07-04-2005 + txdesc->txdes0.ui = 0; + txdesc->txdes0.ubit.TxDMAOwn = 1; +#else // add by Victor Yu. 07-04-2005 + txdesc->txdes0.ui = TXDMA_OWN; +#endif + + outl(0xffffffff, dev->base_addr+TXPD_REG_OFFSET); // start to send packet +#if 0 + dbg_printk("TxDescNow=%d, address=0x%x, des0=0x%x, des1=0x%x\n", priv->TxDescNow, (unsigned int)&priv->virtTxDescBaseAddr[priv->TxDescNow], txdesc->txdes0.ui, txdesc->txdes1.ui); + dbg_printk("Buffer phy address=0x%x, virt=0x%x\n", txdesc->txdes2.phyTxBufBaseAddr, (unsigned int)txdesc->txdes2.virtTxBufBaseAddr); + dbg_printk("TxDescNow-1=%d, address=0x%x, des0=0x%x\n", (priv->TxDescNow-1)&TX_DESC_NUM_MASK, (unsigned int)&priv->virtTxDescBaseAddr[(priv->TxDescNow-1)&TX_DESC_NUM_MASK], priv->virtTxDescBaseAddr[(priv->TxDescNow-1)&TX_DESC_NUM_MASK].txdes0.ui); +#endif + txnow++; + txnow &= TX_DESC_NUM_MASK; + priv->TxDescNow = txnow; + dev->trans_start = jiffies; + priv->stats.tx_packets++; + priv->stats.tx_bytes += len; + +xmit_final: + spin_unlock(&priv->txlock); + dev_kfree_skb_any(skb); + + return 0; +} + +static int mcpu_mac_open(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + unsigned long flags; + + dbg_printk("mcpu_mac_open test01\n"); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#ifdef USE_SCHEDULE_WORK + spin_lock(&priv->rxlock); +#endif + spin_lock(&priv->txlock); + mcpu_mac_reset(dev); + mcpu_mac_set_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, dev->dev_addr); + mcpu_mac_setup_desc_ring(dev); + mcpu_mac_enable(dev); + spin_unlock(&priv->txlock); +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + netif_start_queue(dev); + dbg_printk("IMR=0x%x, MACCR=0x%x\n", inl(dev->base_addr+IMR_REG_OFFSET), inl(dev->base_addr+MACCR_REG_OFFSET)); +#ifdef MCPU_MAC_DEBUG + { + unsigned char macaddr[6]; + int i; + mcpu_mac_get_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, macaddr); + printk("Get MAC address = "); + for ( i=0; i<6; i++ ) + printk("%02X ", macaddr[i]); + printk("\n"); + } +#endif + + return 0; +} + +static int mcpu_mac_stop(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + unsigned long flags; + + dbg_printk("mcpu_mac_stop test01\n"); + netif_stop_queue(dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_save(flags); +#else + save_flags(flags); + cli(); +#endif // LINUX_VERSION_CODE +#ifdef USE_SCHEDULE_WORK + spin_lock(&priv->rxlock); +#endif + spin_lock(&priv->txlock); + outl(0, dev->base_addr+IMR_REG_OFFSET); // disable all interrupt + outl(0, dev->base_addr+MACCR_REG_OFFSET); // disable all function + spin_unlock(&priv->txlock); +#ifdef USE_SCHEDULE_WORK + spin_unlock(&priv->rxlock); +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007 + local_irq_restore(flags); +#else + restore_flags(flags); +#endif // LINUX_VERSION_CODE + + return 0; +} + +static struct net_device_stats *mcpu_mac_get_stats(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + + dbg_printk("mcpu_mac_get_stats test01\n"); +#if 0 + { + unsigned int base=dev->base_addr; + int desc=priv->RxDescNow; + dbg_printk("RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", desc, priv->phyRxDescBaseAddr+(desc*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[desc], priv->virtRxDescBaseAddr[desc].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[desc].rxdes2.virtRxBufBaseAddr); + dbg_printk("Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[desc].rxdes0.ui, priv->virtRxDescBaseAddr[desc].rxdes1.ui); + desc++; + desc &= RX_DESC_NUM_MASK; + dbg_printk("Next RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", desc, priv->phyRxDescBaseAddr+(desc*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[desc], priv->virtRxDescBaseAddr[desc].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[desc].rxdes2.virtRxBufBaseAddr); + dbg_printk("Next Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[desc].rxdes0.ui, priv->virtRxDescBaseAddr[desc].rxdes1.ui); + printk("TX_MCOL_TX_SCOL register = 0x%x\n", inl(base+TX_MCOL_TX_SCOL_REG_OFFSET)); + printk("RPF_AEP register = 0x%x\n", inl(base+RPF_AEP_REG_OFFSET)); + printk("XM_PG register = 0x%x\n", inl(base+XM_PG_REG_OFFSET)); + printk("RUNT_CNT_TLCC register = 0x%x\n", inl(base+RUNT_CNT_TLCC_REG_OFFSET)); + printk("CRCER_CNT_FTL_CNT register = 0x%x\n", inl(base+CRCER_CNT_FTL_CNT_REG_OFFSET)); + printk("RLC_RCC register = 0x%x\n", inl(base+RLC_RCC_REG_OFFSET)); + printk("BROC register = 0x%x\n", inl(base+BROC_REG_OFFSET)); + printk("MUCLA register = 0x%x\n", inl(base+MULCA_REG_OFFSET)); + printk("RP register = 0x%x\n", inl(base+RP_REG_OFFSET)); + printk("XP register = 0x%x\n", inl(base+XP_REG_OFFSET)); + } +#endif + + return &priv->stats; +} + +static irqreturn_t mcpu_mac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev=(struct net_device *)dev_id; + unsigned int ists; +#ifdef USE_SCHEDULE_WORK + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; +#endif + + //dbg_printk("mcpu_mac_interrupt test01\n"); + ists = inl(dev->base_addr+ISR_REG_OFFSET); + if ( ists & RPKT_FINISH ) { +#ifdef USE_SCHEDULE_WORK + schedule_work(&priv->rqueue); +#else + mcpu_mac_recv((void *)dev); +#endif + } else { +#ifdef MCPU_MAC_DEBUG + if ( ists & NORXBUF ) { + printk("Receiver no Rx buffer interrupt\n"); + outl(inl(dev->base_addr+IMR_REG_OFFSET)&~NORXBUF_M, dev->base_addr+IMR_REG_OFFSET); + //return IRQ_HANDLED; + } + if ( ists & AHB_ERR ) { + printk("Receiver AHB error interrupt.\n"); + //return IRQ_HANDLED; + } +#endif + //return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int mcpu_mac_init(struct net_device *dev) +{ + mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv; + + dbg_printk("mcpu_mac_init test01\n"); + + // first initialize the private variable to zero + memset((void *)priv, 0, sizeof(mcpu_mac_priv_t)); + spin_lock_init(&priv->txlock); + spin_lock_init(&priv->rxlock); +#if 1 // add by Victor Yu. 07-04-2005 + INIT_WORK(&priv->rqueue, &mcpu_mac_recv, (void *)dev); +#endif + + // allocate the descriptor and buffer memory + priv->virtTxDescBaseAddr = (tx_desc_t *)kmalloc(sizeof(tx_desc_t)*TX_DESC_NUM, GFP_KERNEL); + if ( priv->virtTxDescBaseAddr == NULL || ((unsigned int)priv->virtTxDescBaseAddr & 0x0f) ) { + dbg_printk("Allocate the Tx descriptor memory fail !\n"); + goto init_fail; + } + priv->phyTxDescBaseAddr = (unsigned int)priv->virtTxDescBaseAddr; + + priv->virtRxDescBaseAddr = (rx_desc_t *)kmalloc(sizeof(rx_desc_t)*RX_DESC_NUM, GFP_KERNEL); + if ( priv->virtRxDescBaseAddr == NULL || ((unsigned int)priv->virtRxDescBaseAddr & 0x0f) ) { + dbg_printk("Allocate the Rx descriptor memory fail !\n"); + goto init_fail; + } + priv->phyRxDescBaseAddr = (unsigned int)priv->virtRxDescBaseAddr; + + priv->virtTxBufBaseAddr = (unsigned char *)kmalloc(TX_BUF_SIZE*TX_DESC_NUM, GFP_KERNEL); + if ( priv->virtTxBufBaseAddr == NULL || ((unsigned int)priv->virtTxBufBaseAddr & 0x03) ) { + dbg_printk("Allocate the Tx buffer memory fail !\n"); + goto init_fail; + } + priv->phyTxBufBaseAddr = (unsigned int)priv->virtTxBufBaseAddr; + + priv->virtRxBufBaseAddr = (unsigned char *)kmalloc(RX_BUF_SIZE*RX_DESC_NUM, GFP_KERNEL); + if ( priv->virtRxBufBaseAddr == NULL || ((unsigned int)priv->virtRxBufBaseAddr & 0x03) ) { + dbg_printk("Allocate the Rx buffer memory fail !\n"); + goto init_fail; + } + priv->phyRxBufBaseAddr = (unsigned int)priv->virtRxBufBaseAddr; + + // setup the thernet basic + ether_setup(dev); + + // reset the MAC + mcpu_mac_reset(dev); + mcpu_mac_setup_desc_ring(dev); + + // we need to get the MAC address from the hardware and set to the device +#if 0 +dev->dev_addr[0] = 0x00; +dev->dev_addr[1] = 0x90; +dev->dev_addr[2] = 0xE8; +dev->dev_addr[3] = 0x92; +dev->dev_addr[4] = 0x20; +if ( priv == (void *)&mcpu_mac_priv ) { // LAN 1 + dev->dev_addr[5] = 0x70; +} else { // LAN2 + dev->dev_addr[5] = 0x71; +} +#else + /* Jimmy_chen@moxa.com.tw : get mac from flash */ + if ( priv == (void *)&mcpu_mac_priv ) { // LAN 1 + dev->dev_addr[0] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET); + dev->dev_addr[1] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET+1); + dev->dev_addr[2] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET+2); + dev->dev_addr[3] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET+3); + dev->dev_addr[4] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET+4); + dev->dev_addr[5] = inb(CONFIG_FLASH_MEM_BASE+ETH1_OFFSET+5); + } else { // LAN2 + dev->dev_addr[0] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET); + dev->dev_addr[1] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET+1); + dev->dev_addr[2] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET+2); + dev->dev_addr[3] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET+3); + dev->dev_addr[4] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET+4); + dev->dev_addr[5] = inb(CONFIG_FLASH_MEM_BASE+ETH2_OFFSET+5); + } +#endif + + // setup the low lever interrupt for Moxa CPU + cpe_int_set_irq(dev->irq, LEVEL, H_ACTIVE); + if ( request_irq(dev->irq, &mcpu_mac_interrupt, SA_INTERRUPT, dev->name, dev) ) { + dbg_printk("Request interrupt service fail !\n"); + goto init_fail; + } + + return 0; + +init_fail: + mcpu_mac_free_memory(dev); + return -ENOMEM; +} + +static struct net_device mcpu_mac_dev = { + .name = "eth0", + .base_addr = IO_ADDRESS(CPE_FTMAC_BASE), + .irq = IRQ_MAC, + .init = &mcpu_mac_init, + .get_stats = &mcpu_mac_get_stats, + .open = &mcpu_mac_open, + .stop = &mcpu_mac_stop, + .hard_start_xmit= &mcpu_mac_hard_start_xmit, + .priv = (void *)&mcpu_mac_priv, + .tx_timeout = &mcpu_mac_tx_timeout, + .do_ioctl = &mcpu_mac_iotcl , +#ifdef HAVE_MULTICAST + .set_multicast_list = &mcpu_mac_set_multicast_list, +#endif +}; + +#ifdef CONFIG_ARCH_MOXART + #if !defined(CONFIG_ARCH_W325_EC) && !defined(CONFIG_ARCH_EM1220_APIT) +static struct net_device mcpu_mac_dev2 = { + .name = "eth1", + .base_addr = IO_ADDRESS(CPE_FTMAC2_BASE), + .irq = IRQ_MAC2, + .init = &mcpu_mac_init, + .get_stats = &mcpu_mac_get_stats, + .open = &mcpu_mac_open, + .stop = &mcpu_mac_stop, + .hard_start_xmit= &mcpu_mac_hard_start_xmit, + .priv = (void *)&mcpu_mac_priv2, + .tx_timeout = &mcpu_mac_tx_timeout, + .do_ioctl = &mcpu_mac_iotcl , + #ifdef HAVE_MULTICAST + .set_multicast_list = &mcpu_mac_set_multicast_list, + #endif // HAVE_MULTICAST +}; + #endif +#endif // CONFIG_ARCH_MOXART + +static int __init mcpu_mac_init_module(void) +{ + int ret; + + printk("Moxa CPU Ethernet Device Driver Version 1.0 load "); + ret = register_netdev(&mcpu_mac_dev); + if ( ret ) { + printk("fail !\n"); + return ret; + } + +#ifdef CONFIG_ARCH_MOXART + #if !defined(CONFIG_ARCH_W325_EC) && !defined(CONFIG_ARCH_EM1220_APIT) + ret = register_netdev(&mcpu_mac_dev2); + if ( ret ) { + mcpu_mac_free_memory(&mcpu_mac_dev); + free_irq(mcpu_mac_dev.irq, &mcpu_mac_dev); + unregister_netdev(&mcpu_mac_dev); + printk("fail !\n"); + return ret; + } + #endif +#endif // CONFIG_ARCH_MOXART + + printk("OK.\n"); + + return 0; +} + +static void __exit mcpu_mac_cleanup_module(void) +{ + printk("Moxa CPU Ethernet Device Driver unload.\n"); + mcpu_mac_free_memory(&mcpu_mac_dev); + free_irq(mcpu_mac_dev.irq, &mcpu_mac_dev); + unregister_netdev(&mcpu_mac_dev); + +#ifdef CONFIG_ARCH_MOXART + #if !defined(CONFIG_ARCH_W325_EC) && !defined(CONFIG_ARCH_EM1220_APIT) + mcpu_mac_free_memory(&mcpu_mac_dev2); + free_irq(mcpu_mac_dev2.irq, &mcpu_mac_dev2); + unregister_netdev(&mcpu_mac_dev2); + #endif +#endif // CONFIG_ARCH_MOXART +} + +module_init(mcpu_mac_init_module); +module_exit(mcpu_mac_cleanup_module); diff --git a/drivers/net/arm/eth_moxa.h b/drivers/net/arm/eth_moxa.h new file mode 100644 index 00000000..34285b4e --- /dev/null +++ b/drivers/net/arm/eth_moxa.h @@ -0,0 +1,359 @@ + +/* + * This file is the define for Moxa CPU MAC controller. + * + * History: + * Date Author Comment + * 06-15-2005 Victor Yu. Create it. + */ +#ifndef _MOXACPU_MAC_H +#define _MOXACPU_MAC_H + +typedef struct tx_desc_struct { + // TXDES0 + union { + unsigned int ui; +#define TXDMA_OWN (1<<31) +#define TXPKT_EXSCOL (1<<1) +#define TXPKT_LATECOL (1<<0) + struct { + unsigned int TxPktLateCol:1; // is aborted due to late collision + unsigned int TxPktExsCol:1; // is aborted after 16 collisions + unsigned int Reserved1:29; + unsigned int TxDMAOwn:1; // is owned by the MAC controller + } ubit; + } txdes0; + + // TXDES1 + union { + unsigned int ui; +#define EDOTR (1<<31) +#define TXIC (1<<30) +#define TX2FIC (1<<29) +#define FTS (1<<28) +#define LTS (1<<27) +#define TXBUF_SIZE_MASK 0x7ff +#define TXBUF_SIZE_MAX (TXBUF_SIZE_MASK+1) + struct { + unsigned int TxBufSize:11; // transmit buffer size in byte + unsigned int Reserved2:16; + unsigned int Lts:1; // is the last descriptor of a Tx + // packet + unsigned int Fts:1; // is the first descriptor of a Tx + // packet + unsigned int Tx2fic:1; // transmit to FIFO interrupt on + // completion + unsigned int Txic:1; // transmit interrupt on completion + unsigned int Edotr:1; // end descriptor of transmit ring + } ubit; + } txdes1; + + // TXDES2 + struct { + unsigned int phyTxBufBaseAddr;// transmit buffer physical base address + unsigned char *virtTxBufBaseAddr;// transmit buffer virtual base address + } txdes2; +} tx_desc_t; + +typedef struct rx_desc_struct { + // RXDES0 + union { + unsigned int ui; +#define RXDMA_OWN (1<<31) +#define FRS (1<<29) +#define LRS (1<<28) +#define RX_ODD_NB (1<<22) +#define RUNT (1<<21) +#define FTL (1<<20) +#define CRC_ERR (1<<19) +#define RX_ERR (1<<18) +#define BROADCAST_RXDES0 (1<<17) +#define MULTICAST_RXDES0 (1<<16) +#define RFL_MASK 0x7ff +#define RFL_MAX (RFL_MASK+1) + struct { + unsigned int RecvFrameLen:11; // receive frame length + unsigned int Reserved1:5; + unsigned int Multicast:1; // multicast frame + unsigned int Broadcast:1; // broadcast frame + unsigned int RxErr:1; // receive error + unsigned int CRCErr:1; // CRC error + unsigned int Ftl:1; // frame too long + unsigned int Runt:1; // runt packet, less than 64 bytes + unsigned int RxOddNb:1; // receive odd nibbles + unsigned int Reserved2:5; + unsigned int Lrs:1; // last receive segment descriptor + unsigned int Frs:1; // first receive segment descriptor + unsigned int Reserved3:1; + unsigned int RxDMAOwn:1; // RXDMA onwership + } ubit; + } rxdes0; + + // RXDES1 + union { + unsigned int ui; +#define EDORR (1<<31) +#define RXBUF_SIZE_MASK 0x7ff +#define RXBUF_SIZE_MAX (RXBUF_SIZE_MASK+1) + struct { + unsigned int RxBufSize:11; // receive buffer size + unsigned int Reserved4:20; + unsigned int Edorr:1; // end descriptor of receive ring + } ubit; + } rxdes1; + + // RXDES2 + struct { + unsigned int phyRxBufBaseAddr;// receive buffer physical base address + unsigned char *virtRxBufBaseAddr;// receive buffer virtual base address + } rxdes2; +} rx_desc_t; + +typedef struct mac_control_reg_struct { + unsigned int isr; // interrupt status, 0x0 +#define RPKT_FINISH (1<<0) // RXDMA has received packets into RX buffer + // successfully +#define NORXBUF (1<<1) // receive buffer unavailable +#define XPKT_FINISH (1<<2) // TXDMA has moved data into the TX FIFO +#define NOTXBUF (1<<3) // transmit buffer unavailable +#define XPKT_OK_INT_STS (1<<4) // packets transmitted to ethernet successfully +#define XPKT_LOST_INT_STS (1<<5) // packets transmitted to ethernet lost due to late + // collision or excessive collision +#define RPKT_SAV (1<<6) // packets received into RX FIFO successfully +#define RPKT_LOST_INT_STS (1<<7) // received packet lost due to RX FIFO full +#define AHB_ERR (1<<8) // AHB error +#define PHYSTS_CHG (1<<9) // PHY link status change + unsigned int imr; // interrupt mask, 0x4 +#define RPKT_FINISH_M (1<<0) // interrupt mask of ISR[0] +#define NORXBUF_M (1<<1) // interrupt mask of ISR[1] +#define XPKT_FINISH_M (1<<2) // interrupt mask of ISR[2] +#define NOTXBUF_M (1<<3) // interrupt mask of ISR[3] +#define XPKT_OK_M (1<<4) // interrupt mask of ISR[4] +#define XPKT_LOST_M (1<<5) // interrupt mask of ISR[5] +#define RPKT_SAV_M (1<<6) // interrupt mask of ISR[6] +#define RPKT_LOST_M (1<<7) // interrupt mask of ISR[7] +#define AHB_ERR_M (1<<8) // interrupt mask of ISR[8] +#define PHYSTS_CHG_M (1<<9) // interrupt mask of ISR[9] + unsigned int mac_madr; // MAC most significant address, 0x8 +#define MAC_MADR_MASK 0xffff // the most significant 2 bytes of MAC address + unsigned int mac_ldar; // MAC least significant address, 0xc + unsigned int matht0; // multicast address hash table 0, 0x10 + unsigned int matht1; // multicast address hash table 1, 0x14 + unsigned int txpd; // transmit poll demand, 0x18 + unsigned int rxpd; // receive poll demand, 0x1c + unsigned int txr_badr; // transmit ring base address, 0x20 + unsigned int rxr_badr; // receive ring base address, 0x24 + unsigned int itc; // interrupt timer control, 0x28 +#define TXINT_TIME_SEL (1<<15) // defines the period of TX cycle time +#define TXINT_THR_MASK (1<<14|1<13|1<12) +#define TXINT_CNT_MASK (1<<11|1<<10|1<<9|1<<8) +#define RXINT_TIME_SEL (1<<7) // defines the period of RX cycle time +#define RXINT_THR_MASK (1<<6|1<<5|1<<4) +#define RXINT_CNT_MASK (1<<3|1<<2|1<<1|1<<0) + unsigned int aptc; // automatic polling timer control, 0x2c +#define TXPOLL_TIME_SEL (1<<12) // defines the period of TX poll time +#define TXPOLL_CNT_MASK (1<<11|1<<10|1<<9|1<<8) +#define TXPOLL_CNT_SHIFT_BIT 8 +#define RXPOLL_TIME_SEL (1<<4) // defines the period of RX poll time +#define RXPOLL_CNT_MASK (1<<3|1<<2|1<<1|1<<0) +#define RXPOLL_CNT_SHIFT_BIT 0 + unsigned int dblac; // DMA burst length and arbitration control, 0x30 +#define RX_THR_EN (1<<9) // enable RX FIFO threshold arbitration +#define RXFIFO_HTHR_MASK (1<<8|1<<7|1<<6) +#define RXFIFO_LTHR_MASK (1<<5|1<<4|1<<3) +#define INCR16_EN (1<<2) // use INCR16 burst command in AHB bus +#define INCR8_EN (1<<1) // use INCR8 burst command in AHB bus +#define INCR4_EN (1<<0) // use INCR4 burst command in AHB bus + unsigned int reserved1[21]; // 0x34 - 0x84 + unsigned int maccr; // MAC control, 0x88 +#define RX_BROADPKT (1<<17) // receive boradcast packet +#define RX_MULTIPKT (1<<16) // receive all multicast packet +#define FULLDUP (1<<15) // full duplex +#define CRC_APD (1<<14) // append CRC to transmitted packet +#define RCV_ALL (1<<12) // not check incoming packet's dest. address +#define RX_FTL (1<<11) // store incoming packet even if its length is + // great than 1518 bytes +#define RX_RUNT (1<<10) // store incoming packet even if its length is + // less than 64 bytes +#define HT_MULTI_EN (1<<9) // enable storing incoming packet if the packet + // passes hash table address filtering and is a + // multicast packet +#define RCV_EN (1<<8) // receiver enable +#define ENRX_IN_HALFTX (1<<6) // enable packet reception when transmitting + // packet in half duplex mode +#define XMT_EN (1<<5) // transmitter enable +#define CRC_DIS (1<<4) // disable CRC check when receiving packets +#define LOOP_EN (1<<3) // internal loop-back +#define SW_RST (1<<2) // software reset, last 64 AHB bus clocks +#define RDMA_EN (1<<1) // enable receive DMA channel +#define XDMA_EN (1<<0) // enable transmit DMA channel + unsigned int macsr; // MAC status, 0x8c +#define COL_EXCEED (1<<11) // collision amount exceeds 16 +#define LATE_COL (1<<10) // transmitter detects late collision +#define XPKT_LOST (1<<9) // packet transmitted to ethernet lost due to late + // collision or excessive collision +#define XPKT_OK (1<<8) // packets transmitted to ethernet successfully +#define RUNT_MAC_STS (1<<7) // receiver detects a runt packet +#define FTL_MAC_STS (1<<6) // receiver detects a frame that is too long +#define CRC_ERR_MAC_STS (1<<5) +#define RPKT_LOST (1<<4) // received packets list due to RX FIFO full +#define RPKT_SAVE (1<<3) // packets received into RX FIFO successfully +#define COL (1<<2) // incoming packet dropped due to collision +#define MCPU_BROADCAST (1<<1) +#define MCPU_MULTICAST (1<<0) + unsigned int phycr; // PHY control, 0x90 +#define MIIWR (1<<27) // initialize a write sequence to PHY by setting + // this bit to 1. This bit would be auto cleared + // after the write operation is finished. +#define MIIRD (1<<26) +#define REGAD_MASK (1<<25|1<<24|1<<23|1<<22|1<<21) +#define PHYAD_MASK (1<<20|1<<19|1<<18|1<<17|1<<16) +#define MIIRDATA_MASK 0xffff + unsigned int phywdata; // PHY write data, 0x94 +#define MIIWDATA_MASK 0xffff + unsigned int fcr; // flow control, 0x98 +#define PAUSE_TIME_MASK 0xffff0000 +#define FC_HIGH_MASK (1<<15|1<<14|1<<13|1<<12) +#define FC_LOW_MASK (1<<11|1<<10|1<<9|1<<8) +#define RX_PAUSE (1<<4) // receive pause frame +#define TXPAUSED (1<<3) // packet transmission is paused due to receive + // pause frame +#define FCTHR_EN (1<<2) // enable flow control threshold mode. +#define TX_PAUSE (1<<1) // transmit pause frame +#define FC_EN (1<<0) // flow control mode enable + unsigned int bpr; // back pressure, 0x9c +#define BK_LOW_MASK (1<<11|1<<10|1<<9|1<<8) +#define BKJAM_LEN_MASK (1<<7|1<<6|1<<5|1<<4) +#define BK_MODE (1<<1) // back pressure address mode +#define BK_EN (1<<0) // back pressure mode enable + unsigned int reserved2[9]; // 0xa0 - 0xc0 + unsigned int ts; // test seed, 0xc4 +#define TEST_SEED_MASK 0x3fff + unsigned int dmafifos; // DMA/FIFO state, 0xc8 +#define TXD_REQ (1<<31) // TXDMA request +#define RXD_REQ (1<<30) // RXDMA request +#define DARB_TXGNT (1<<29) // TXDMA grant +#define DARB_RXGNT (1<<28) // RXDMA grant +#define TXFIFO_EMPTY (1<<27) // TX FIFO is empty +#define RXFIFO_EMPTY (1<<26) // RX FIFO is empty +#define TXDMA2_SM_MASK (1<<14|1<<13|1<<12) +#define TXDMA1_SM_MASK (1<<11|1<<10|1<<9|1<<8) +#define RXDMA2_SM_MASK (1<<6|1<<5|1<<4) +#define RXDMA1_SM_MASK (1<<3|1<<2|1<<1|1<<0) + unsigned int tm; // test mode, 0xcc +#define SINGLE_PKT (1<<26) // single packet mode +#define PTIMER_TEST (1<<25) // automatic polling timer test mode +#define ITIMER_TEST (1<<24) // interrupt timer test mode +#define TEST_SEED_SEL (1<<22) // test seed select +#define SEED_SEL (1<<21) // seed select +#define TEST_MODE (1<<20) // transmission test mode +#define TEST_TIME_MASK (1<<19|1<<18|1<<17|1<<16|1<<15|1<<14|1<<13|1<<12|1<<11|1<<10) +#define TEST_EXCEL_MASK (1<<9|1<<8|1<<7|1<<6|1<<5) + unsigned int reserved3; // 0xd0 + unsigned int txmcol_xscol; // TX_MCOL and TX_SCOL counter, 0xd4 +#define TX_MCOL_MASK 0xffff0000 +#define TX_MCOL_SHIFT_BIT 16 +#define TX_SCOL_MASK 0xffff +#define TX_SCOL_SHIFT_BIT 0 + unsigned int rpf_aep; // RPF and AEP counter, 0xd8 +#define RPF_MASK 0xffff0000 +#define RPF_SHIFT_BIT 16 +#define AEP_MASK 0xffff +#define AEP_SHIFT_BIT 0 + unsigned int xm_pg; // XM and PG counter, 0xdc +#define XM_MASK 0xffff0000 +#define XM_SHIFT_BIT 16 +#define PG_MASK 0xffff +#define PG_SHIFT_BIT 0 + unsigned int runtcnt_tlcc; // RUNT_CNT and TLCC counter, 0xe0 +#define RUNT_CNT_MASK 0xffff0000 +#define RUNT_CNT_SHIFT_BIT 16 +#define TLCC_MASK 0xffff +#define TLCC_SHIFT_BIT 0 + unsigned int crcercnt_ftlcnt; // CRCER_CNT and FTL_CNT counter, 0xe4 +#define CRCER_CNT_MASK 0xffff0000 +#define CRCER_CNT_SHIFT_BIT 16 +#define FTL_CNT_MASK 0xffff +#define FTL_CNT_SHIFT_BIT 0 + unsigned int rlc_rcc; // RLC and RCC counter, 0xe8 +#define RLC_MASK 0xffff0000 +#define RLC_SHIFT_BIT 16 +#define RCC_MASK 0xffff +#define RCC_SHIFT_BIT 0 + unsigned int broc; // BROC counter, 0xec + unsigned int mulca; // MULCA counter, 0xf0 + unsigned int rp; // RP counter, 0xf4 + unsigned int xp; // XP counter, 0xf8 +} mac_control_reg_t; + +#define ISR_REG_OFFSET 0x00 +#define IMR_REG_OFFSET 0x04 +#define MAC_MADR_REG_OFFSET 0x08 +#define MAC_LADR_REG_OFFSET 0x0C +#define MATH0_REG_OFFSET 0x10 +#define MATH1_REG_OFFSET 0x14 +#define TXPD_REG_OFFSET 0x18 +#define RXPD_REG_OFFSET 0x1C +#define TXR_BADR_REG_OFFSET 0x20 +#define RXR_BADR_REG_OFFSET 0x24 +#define ITC_REG_OFFSET 0x28 +#define APTC_REG_OFFSET 0x2C +#define DBLAC_REG_OFFSET 0x30 +#define MACCR_REG_OFFSET 0x88 +#define MACSR_REG_OFFSET 0x8C +#define PHYCR_REG_OFFSET 0x90 +#define PHYWDATA_REG_OFFSET 0x94 +#define FCR_REG_OFFSET 0x98 +#define BPR_REG_OFFSET 0x9C +#define TS_REG_OFFSET 0xC4 +#define DMAFIFOS_REG_OFFSET 0xC8 +#define TM_REG_OFFSET 0xCC +#define TX_MCOL_TX_SCOL_REG_OFFSET 0xD4 +#define RPF_AEP_REG_OFFSET 0xD8 +#define XM_PG_REG_OFFSET 0xDC +#define RUNT_CNT_TLCC_REG_OFFSET 0xE0 +#define CRCER_CNT_FTL_CNT_REG_OFFSET 0xE4 +#define RLC_RCC_REG_OFFSET 0xE8 +#define BROC_REG_OFFSET 0xEC +#define MULCA_REG_OFFSET 0xF0 +#define RP_REG_OFFSET 0xF4 +#define XP_REG_OFFSET 0xF8 + +/* Jimmy_chen@moxa.com.tw : phy ctrl register */ +#define PHY_CNTL_REG 0x00 +#define PHY_STATUS_REG 0x01 +#define PHY_ID_REG1 0x02 +#define PHY_ID_REG2 0x03 +#define PHY_ANA_REG 0x04 +#define PHY_ANLPAR_REG 0x05 +#define PHY_ANE_REG 0x06 +#define PHY_ECNTL_REG1 0x10 +#define PHY_QPDS_REG 0x11 +#define PHY_10BOP_REG 0x12 +#define PHY_ECNTL_REG2 0x13 +#define FTMAC100_REG_PHY_WRITE 0x08000000 +#define FTMAC100_REG_PHY_READ 0x04000000 +/* PHY Status register */ +#define AN_COMPLETE 0x0020 +#define Link_Status 0x0004 +typedef struct mcpu_mac_priv_struct { + unsigned int phyTxDescBaseAddr; // Tx descriptor physical base address + tx_desc_t *virtTxDescBaseAddr; // Tx descriptor virtual base address + unsigned int phyRxDescBaseAddr; // Rx descriptor physical base address + rx_desc_t *virtRxDescBaseAddr; // Rx descriptor virtual base address + unsigned int phyTxBufBaseAddr; // Tx buffer physical base address + unsigned char *virtTxBufBaseAddr; // Tx buffer virtual base address + unsigned int phyRxBufBaseAddr; // Rx buffer physical base address + unsigned char *virtRxBufBaseAddr; // Rx buffer virtual base address + int TxDescNow; // Tx descriptor now first used index + int RxDescNow; // Rx descriptor now first used index + struct net_device_stats stats; // OS about the ethernet statistics + spinlock_t txlock; + spinlock_t rxlock; + unsigned int maccr; // store the maccr control register value +#if 1 // add by Victor Yu. 07-04-2005 + struct work_struct rqueue; +#endif +} mcpu_mac_priv_t; + +#endif // MOXACPU_MAC_H diff --git a/drivers/net/arm/eth_s3c4510b.c b/drivers/net/arm/eth_s3c4510b.c new file mode 100644 index 00000000..ed425665 --- /dev/null +++ b/drivers/net/arm/eth_s3c4510b.c @@ -0,0 +1,512 @@ +/* + * linux/drivers/net/arm/eth_s3c4510b.c + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Re-written from scratch for 2.6.x after studying the original 2.4.x + * driver by Mac Wang. + * + * Copyright (C) 2002 Mac Wang + * + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "eth_s3c4510b.h" + +#define __DRIVER_NAME "Samsung S3C4510B Ethernet Driver version 0.2 (2004-06-13) " + +#define _SDEBUG +#ifdef _SDEBUG +# define _DPRINTK(format, args...) \ + printk (KERN_INFO "%s():%05d "format".\n" , __FUNCTION__ , __LINE__ , ## args); +#else +# define _DPRINTK(format, args...) +#endif + +#define _EPRINTK(format, args...) \ + printk (KERN_ERR "%s():%05d "format".\n" , __FUNCTION__ , __LINE__ , ## args); + +struct eth_priv { + + /* Frame Descriptors */ + TX_FrameDesc m_txFDbase[ETH_NTxFrames]; /* array of TX frame descriptors */ + RX_FrameDesc m_rxFDbase[ETH_NRxFrames]; /* array of RX frame descriptors */ + volatile TX_FrameDesc *m_curTX_FD; /* current TX FD to queue */ + volatile TX_FrameDesc *m_oldTX_FD; /* oldest TX FD queued, but not transmitted */ + volatile RX_FrameDesc *m_curRX_FD; /* current RX FD to receive */ + + struct net_device_stats stats; + spinlock_t lock; +}; + +/* This struct must be 16 byte aligned */ +struct skb_priv { + volatile RX_FrameDesc *m_RxFD; + struct net_device *m_dev; + u32 m_pad[2]; +}; + +static s32 __skb_head_offset; + +/** + ** Avoid memcpy in RX handler by pre-allocating the socket buffers + **/ + +// static void __skb_destruct( struct sk_buff *skb); +static void __skb_prepare( struct net_device *dev, volatile RX_FrameDesc *pRxFD) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb( sizeof(ETHFrame) + 16 + 2); + if ( unlikely(!skb)) { + _EPRINTK(" unable to allocate skb..."); + } + +// _DPRINTK("allocate skb: 0x%08x", (u32)skb); + + skb->dev = dev; + + /* attach skb to FD */ + pRxFD->skb = skb; + pRxFD->m_frameDataPtr.bf.dataPtr = (u32)skb->data | CACHE_DISABLE_MASK; + pRxFD->m_frameDataPtr.bf.owner = 0x1; /* BDMA owner */ + +} + +static s32 RxFDinit( struct net_device *dev) { + + struct eth_priv *priv = (struct eth_priv *) dev->priv; + s32 i; + volatile RX_FrameDesc *rxFDbase; + struct sk_buff *skb; + + /* determine skb initial headroom for later use in the skb destructor */ + skb = dev_alloc_skb(256); + __skb_head_offset = skb_headroom( skb); + dev_kfree_skb( skb); + + /* store start of Rx descriptors and set current */ + rxFDbase = priv->m_curRX_FD = + (RX_FrameDesc *)((u32)priv->m_rxFDbase | CACHE_DISABLE_MASK); + for ( i = 0; i < ETH_NRxFrames; i++) { + __skb_prepare( dev, &rxFDbase[i]); + priv->m_rxFDbase[i].m_reserved = 0x0; + priv->m_rxFDbase[i].m_status.ui = 0x0; + priv->m_rxFDbase[i].m_nextFD = &rxFDbase[i+1]; +// _DPRINTK("rxFDbase[%d]: 0x%08x", i, (u32)&rxFDbase[i]); + } + + /* make the list circular */ + priv->m_rxFDbase[i-1].m_nextFD = &rxFDbase[0]; + + outl( (unsigned int)rxFDbase, REG_BDMARXPTR); + + return 0; +} + +static s32 TxFDinit( struct net_device *dev) { + + struct eth_priv *priv = (struct eth_priv *) dev->priv; + s32 i; + volatile TX_FrameDesc *txFDbase; + + /* store start of Tx descriptors and set current */ + txFDbase = priv->m_curTX_FD = priv->m_oldTX_FD = + (TX_FrameDesc *) ((u32)priv->m_txFDbase | CACHE_DISABLE_MASK); + + for ( i = 0; i < ETH_NTxFrames; i++) { + priv->m_txFDbase[i].m_frameDataPtr.ui = 0x0; /* CPU owner */ + priv->m_txFDbase[i].m_opt.ui = 0x0; + priv->m_txFDbase[i].m_status.ui = 0x0; + priv->m_txFDbase[i].m_nextFD = &txFDbase[i+1]; +// _DPRINTK("txFDbase[%d]: 0x%08x", i, (u32)&txFDbase[i]); + } + + /* make the list circular */ + priv->m_txFDbase[i-1].m_nextFD = &txFDbase[0]; + + outl( (unsigned int)txFDbase, REG_BDMATXPTR); + + return 0; +} + +static irqreturn_t __s3c4510b_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sk_buff *skb; + struct net_device *dev = (struct net_device *) dev_id; + struct eth_priv *priv = (struct eth_priv *) dev->priv; + volatile RX_FrameDesc *pRxFD; + volatile RX_FrameDesc *cRxFD; + + spin_lock(&priv->lock); + + LED_SET(4); + + pRxFD = priv->m_curRX_FD; + cRxFD = (RX_FrameDesc *)inl(REG_BDMARXPTR); + + /* clear received frame bit */ + outl( ETH_S_BRxRDF, REG_BDMASTAT); + + do { + if ( likely( pRxFD->m_status.bf.good)) { + skb = pRxFD->skb; + + __skb_prepare( dev, pRxFD); + + /* reserve two words used by protocol layers */ + skb_reserve(skb, 2); + skb_put(skb, pRxFD->m_status.bf.len); + skb->protocol = eth_type_trans(skb, dev); + priv->stats.rx_packets++; + priv->stats.rx_bytes += pRxFD->m_status.bf.len; + netif_rx(skb); + } + else { + priv->stats.rx_errors++; + if( pRxFD->m_status.bf.overFlow) + priv->stats.rx_fifo_errors++; + if( pRxFD->m_status.bf.overMax) + priv->stats.rx_length_errors++; + if( pRxFD->m_status.bf.crcErr) + priv->stats.rx_crc_errors++; + if( pRxFD->m_status.bf.longErr) + priv->stats.rx_length_errors++; + if( pRxFD->m_status.bf.alignErr) + priv->stats.rx_frame_errors++; + /** + ** No good category for these errors + if( pRxFD->m_status.bf.parityErr) + **/ + + } + + /* set owner back to CPU */ + pRxFD->m_frameDataPtr.bf.owner = 1; + /* clear status */ + pRxFD->m_status.ui = 0x0; + /* advance to next descriptor */ + pRxFD = pRxFD->m_nextFD; + + } while ( pRxFD != cRxFD); + + priv->m_curRX_FD = pRxFD; + + LED_CLR(4); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + +} + +static irqreturn_t __s3c4510b_tx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct eth_priv *priv = (struct eth_priv *) dev->priv; + volatile TX_FrameDesc *pTxFD; + volatile TX_FrameDesc *cTxFD; + + spin_lock(&priv->lock); + + pTxFD = priv->m_oldTX_FD; + cTxFD = (TX_FrameDesc *)inl(REG_BDMATXPTR); + + while ( pTxFD != cTxFD) { + + if ( likely(pTxFD->m_status.bf.complete)) { + priv->stats.tx_packets++; + } + if( pTxFD->m_status.bf.exColl) { + _EPRINTK("TX collision detected"); + priv->stats.tx_errors++; + priv->stats.collisions++; + } + if( pTxFD->m_status.bf.underRun) { + _EPRINTK("TX Underrun detected"); + priv->stats.tx_errors++; + priv->stats.tx_fifo_errors++; + } + if( pTxFD->m_status.bf.noCarrier) { + _EPRINTK("TX no carrier detected"); + priv->stats.tx_errors++; + priv->stats.tx_carrier_errors++; + } + if( pTxFD->m_status.bf.lateColl) { + _EPRINTK("TX late collision detected"); + priv->stats.tx_errors++; + priv->stats.tx_window_errors++; + } + if( pTxFD->m_status.bf.parityErr) { + _EPRINTK("TX parity error detected"); + priv->stats.tx_errors++; + priv->stats.tx_aborted_errors++; + } + + dev_kfree_skb_irq( pTxFD->skb); + pTxFD = pTxFD->m_nextFD; + } + + priv->m_oldTX_FD = pTxFD; + + LED_CLR(3); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + +} + +static int __s3c4510b_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int len; + u32 addr; + struct eth_priv *priv = (struct eth_priv *) dev->priv; + +// _DPRINTK("entered with dev = 0x%08x", (unsigned int)dev); + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + dev->trans_start = jiffies; + + if ( unlikely( priv->m_curTX_FD->m_frameDataPtr.bf.owner)) { + _EPRINTK("Ethernet TX Frame. CPU not owner"); + return -EBUSY; + } + + /* this needs to be word aligned for the BDMA -- round down */ + addr = ((u32)skb->data & ~0x3) | CACHE_DISABLE_MASK; + priv->m_curTX_FD->m_frameDataPtr.bf.dataPtr = addr; + + /* Set TX Frame flags */ + priv->m_curTX_FD->m_opt.bf.widgetAlign = (u32)skb->data - addr; /* compenstate for alignment */ + priv->m_curTX_FD->m_opt.bf.frameDataDir = 1; + priv->m_curTX_FD->m_opt.bf.littleEndian = 1; + priv->m_curTX_FD->m_opt.bf.macTxIrqEnbl = 1; + priv->m_curTX_FD->m_opt.bf.no_crc = 0; + priv->m_curTX_FD->m_opt.bf.no_padding = 0; + + /* Set TX Frame length */ + priv->m_curTX_FD->m_status.bf.len = len; + + priv->m_curTX_FD->skb = skb; + + /* Change ownership to BDMA */ + priv->m_curTX_FD->m_frameDataPtr.bf.owner = 1; + + /* Change the Tx frame descriptor for next use */ + priv->m_curTX_FD = priv->m_curTX_FD->m_nextFD; + + LED_SET(3); + + /* Enable MAC and BDMA Tx control register */ + outl( ETH_BTxBRST | /* BDMA Tx burst size 16 words */ + ETH_BTxMSL110 | /* BDMA Tx wait to fill 6/8 of the BDMA */ + ETH_BTxSTSKO | /* BDMA Tx interrupt(Stop) on non-owner TX FD */ + ETH_BTxEn, /* BDMA Tx Enable */ + REG_BDMATXCON); + + outl( ETH_EnComp | /* interrupt when the MAC transmits or discards packet */ + ETH_TxEn | /* MAC transmit enable */ + ETH_EnUnder | /* interrupt on Underrun */ + ETH_EnNCarr | /* interrupt on No Carrier */ + ETH_EnExColl | /* interrupt if 16 collision occur */ + ETH_EnLateColl | /* interrupt if collision occurs after 512 bit times(64 bytes times) */ + ETH_EnTxPar, /* interrupt if the MAC transmit FIFO has a parity error */ + REG_MACTXCON); + + return 0; + +} + +static struct irqaction __rx_irqaction = { + name: "eth_rx", + flags: SA_INTERRUPT, + handler: __s3c4510b_rx_int, +}; + +static struct irqaction __tx_irqaction = { + name: "eth_tx", + flags: SA_INTERRUPT, + handler: __s3c4510b_tx_int, +}; + +static int __s3c4510b_open(struct net_device *dev) +{ + unsigned long status; + + /* Disable interrupts */ + INT_DISABLE(INT_BDMARX); + INT_DISABLE(INT_MACTX); + + /** + ** install RX ISR + **/ + __rx_irqaction.dev_id = (void *)dev; + status = setup_irq( INT_BDMARX, &__rx_irqaction); + if ( unlikely(status)) { + printk( KERN_ERR "Unabled to hook irq %d for ethernet RX\n", INT_BDMARX); + return status; + } + + /** + ** install TX ISR + **/ + __tx_irqaction.dev_id = (void *)dev; + status = setup_irq( INT_MACTX, &__tx_irqaction); + if ( unlikely(status)) { + printk( KERN_ERR "Unabled to hook irq %d for ethernet TX\n", INT_MACTX); + return status; + } + + /* setup DBMA and MAC */ + outl( ETH_BRxRS, REG_BDMARXCON); /* reset BDMA RX machine */ + outl( ETH_BTxRS, REG_BDMATXCON); /* reset BDMA TX machine */ + outl( ETH_SwReset, REG_MACCON); /* reset MAC machine */ + outl( sizeof( ETHFrame), REG_BDMARXLSZ); + outl( ETH_FullDup, REG_MACCON); /* enable full duplex */ + + /* init frame descriptors */ + TxFDinit( dev); + RxFDinit( dev); + + outl( (dev->dev_addr[0] << 24) | + (dev->dev_addr[1] << 16) | + (dev->dev_addr[2] << 8) | + (dev->dev_addr[3]) , REG_CAM_BASE); + outl( (dev->dev_addr[4] << 24) | + (dev->dev_addr[5] << 16) , REG_CAM_BASE + 4); + + outl( 0x0001, REG_CAMEN); + outl( ETH_CompEn | /* enable compare mode (check against the CAM) */ + ETH_BroadAcc, /* accept broadcast packetes */ + REG_CAMCON); + + INT_ENABLE(INT_BDMARX); + INT_ENABLE(INT_MACTX); + + /* enable RX machinery */ + outl( ETH_BRxBRST | /* BDMA Rx Burst Size 16 words */ + ETH_BRxSTSKO | /* BDMA Rx interrupt(Stop) on non-owner RX FD */ + ETH_BRxMAINC | /* BDMA Rx Memory Address increment */ + ETH_BRxDIE | /* BDMA Rx Every Received Frame Interrupt Enable */ + ETH_BRxNLIE | /* BDMA Rx NULL List Interrupt Enable */ + ETH_BRxNOIE | /* BDMA Rx Not Owner Interrupt Enable */ + ETH_BRxLittle | /* BDMA Rx Little endian */ + ETH_BRxWA10 | /* BDMA Rx Word Alignment- two invalid bytes */ + ETH_BRxEn, /* BDMA Rx Enable */ + REG_BDMARXCON); + + outl( ETH_RxEn | /* enable MAC RX */ + ETH_StripCRC | /* check and strip CRC */ + ETH_EnCRCErr | /* interrupt on CRC error */ + ETH_EnOver | /* interrupt on overflow error */ + ETH_EnLongErr | /* interrupt on long frame error */ + ETH_EnRxPar, /* interrupt on MAC FIFO parity error */ + REG_MACRXCON); + + netif_start_queue(dev); + + return 0; +} + +static int __s3c4510b_stop(struct net_device *dev) +{ + // Disable irqs + INT_DISABLE(INT_BDMARX); + INT_DISABLE(INT_MACTX); + + outl( 0, REG_BDMATXCON); + outl( 0, REG_BDMARXCON); + outl( 0, REG_MACTXCON); + outl( 0, REG_MACRXCON); + + free_irq(INT_BDMARX, dev); + free_irq(INT_MACTX, dev); + + netif_stop_queue(dev); + + return 0; +} + +struct net_device_stats *__s3c4510b_get_stats(struct net_device *dev) +{ + return &((struct eth_priv *)dev->priv)->stats; +} + +/* + * The init function, invoked by register_netdev() + */ +static int __s3c4510b_init(struct net_device *dev) +{ + ether_setup(dev); + + /* assign net_device methods */ + dev->open = __s3c4510b_open; + dev->stop = __s3c4510b_stop; +// dev->ioctl = __s3c4510b_ioctl; + dev->get_stats = __s3c4510b_get_stats; +// dev->tx_timeout = __s3c4510b_tx_timeout; + dev->hard_start_xmit = __s3c4510b_start_xmit; + + dev->irq = INT_BDMARX; + dev->tx_queue_len = ETH_NTxFrames; + dev->dma = 0; + dev->watchdog_timeo = HZ; + + /* set MAC address */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x40; + dev->dev_addr[2] = 0x95; + dev->dev_addr[3] = 0x36; + dev->dev_addr[4] = 0x35; + dev->dev_addr[5] = 0x33; + + SET_MODULE_OWNER(dev); + + dev->priv = kmalloc(sizeof(struct eth_priv), GFP_KERNEL); + if( dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct eth_priv)); + spin_lock_init(&((struct eth_priv *) dev->priv)->lock); + return 0; +} + +struct net_device __s3c4510b_netdevs = { + init: __s3c4510b_init, +}; + +static int __init __s3c4510b_init_module(void) +{ + int status = 0; + + printk(KERN_INFO "%s\n", __DRIVER_NAME); + + if( (status = register_netdev( &__s3c4510b_netdevs))) + printk("S3C4510 eth: Error %i registering interface %s\n", status, __s3c4510b_netdevs.name); + + return status; +} + +static void __exit __s3c4510b_cleanup(void) +{ + kfree( __s3c4510b_netdevs.priv); + unregister_netdev( &__s3c4510b_netdevs); + return; +} + +module_init(__s3c4510b_init_module); +module_exit(__s3c4510b_cleanup); + +MODULE_DESCRIPTION("Samsung S3C4510B ethernet driver"); +MODULE_AUTHOR("Curt Brune "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/arm/eth_s3c4510b.h b/drivers/net/arm/eth_s3c4510b.h new file mode 100644 index 00000000..942f8a66 --- /dev/null +++ b/drivers/net/arm/eth_s3c4510b.h @@ -0,0 +1,301 @@ +#ifndef __ETH_S3C4510B_H +#define __ETH_S3C4510B_H + +/* + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + * + * Description: Ethernet interface + * Runtime Env: ARM7TDMI + * Change History: + * 03-02-04 Create (Curt Brune) curt@cucy.com + * + */ + +#define __packed __attribute__ ((packed)) + +#define ETH_NTxFrames (16) /* Max number of Tx Frames */ +#define ETH_NRxFrames (16) /* Max number of Rx Frames */ + +/* Buffered DMA Receiver Control Register */ +#define ETH_BRxBRST 0x0000F /* BDMA Rx Burst Size * BRxBRST */ + /* = Burst Data Size 16 */ +#define ETH_BRxSTSKO 0x00020 /* BDMA Rx Stop/Skip Frame or Interrupt(=1) */ + /* case of not OWNER the current Frame */ +#define ETH_BRxMAINC 0x00040 /* BDMA Rx Memory Address Inc/Dec */ +#define ETH_BRxDIE 0x00080 /* BDMA Rx Every Received Frame Interrupt Enable */ +#define ETH_BRxNLIE 0x00100 /* BDMA Rx NULL List Interrupt Enable */ +#define ETH_BRxNOIE 0x00200 /* BDMA Rx Not Owner Interrupt Enable */ +#define ETH_BRxMSOIE 0x00400 /* BDMA Rx Maximum Size over Interrupr Enable */ +#define ETH_BRxLittle 0x00800 /* BDMA Rx Big/Little Endian */ +#define ETH_BRxBig 0x00000 /* BDMA Rx Big/Little Endian */ +#define ETH_BRxWA01 0x01000 /* BDMA Rx Word Alignment- one invalid byte */ +#define ETH_BRxWA10 0x02000 /* BDMA Rx Word Alignment- two invalid bytes */ +#define ETH_BRxWA11 0x03000 /* BDMA Rx Word Alignment- three invalid bytes */ +#define ETH_BRxEn 0x04000 /* BDMA Rx Enable */ +#define ETH_BRxRS 0x08000 /* BDMA Rx Reset */ +#define ETH_RxEmpty 0x10000 /* BDMA Rx Buffer empty interrupt */ +#define ETH_BRxEarly 0x20000 /* BDMA Rx Early notify Interrupt */ + +/* Buffered DMA Trasmit Control Register(BDMATXCON) */ +#define ETH_BTxBRST 0x0000F /* BDMA Tx Burst Size = 16 */ +#define ETH_BTxSTSKO 0x00020 /* BDMA Tx Stop/Skip Frame or Interrupt in case */ + /* of not Owner the current frame */ +#define ETH_BTxCPIE 0x00080 /* BDMA Tx Complete to send control */ + /* packet Enable */ +#define ETH_BTxNOIE 0x00200 /* BDMA Tx Buffer Not Owner */ +#define ETH_BTxEmpty 0x00400 /* BDMA Tx Buffer Empty Interrupt */ + +/* BDMA Tx buffer can be moved to the MAC Tx IO when the new frame comes in. */ +#define ETH_BTxMSL000 0x00000 /* No wait to fill the BDMA */ +#define ETH_BTxMSL001 0x00800 /* wait to fill 1/8 of the BDMA */ +#define ETH_BTxMSL010 0x01000 /* wait to fill 2/8 of the BDMA */ +#define ETH_BTxMSL011 0x01800 /* wait to fill 3/8 of the BDMA */ +#define ETH_BTxMSL100 0x02000 /* wait to fill 4/8 of the BDMA */ +#define ETH_BTxMSL101 0x02800 /* wait to fill 5/8 of the BDMA */ +#define ETH_BTxMSL110 0x03000 /* wait to fill 6/8 of the BDMA */ +#define ETH_BTxMSL111 0x03800 /* wait to fill 7/8 of the BDMA */ +#define ETH_BTxEn 0x04000 /* BDMA Tx Enable */ +#define ETH_BTxRS 0x08000 /* BDMA Tx Reset */ + +/* BDMA Status Register */ +#define ETH_S_BRxRDF 0x00001 /* BDMA Rx Done Every Received Frame */ +#define ETH_S_BRxNL 0x00002 /* BDMA Rx NULL List */ +#define ETH_S_BRxNO 0x00004 /* BDMA Rx Not Owner */ +#define ETH_S_BRxMSO 0x00008 /* BDMA Rx Maximum Size Over */ +#define ETH_S_BRxEmpty 0x00010 /* BDMA Rx Buffer Empty */ +#define ETH_S_BRxSEarly 0x00020 /* Early Notify */ +#define ETH_S_BRxFRF 0x00080 /* One more frame data in BDMA receive buffer */ +#define ETH_S_BTxCCP 0x10000 /* BDMA Tx Complete to send Control Packet */ +#define ETH_S_BTxNL 0x20000 /* BDMA Tx Null List */ +#define ETH_S_BTxNO 0x40000 /* BDMA Tx Not Owner */ +#define ETH_S_BTxEmpty 0x100000 /* BDMA Tx Buffer Empty */ + +/* MAC Control Register */ +#define ETH_HaltReg 0x0001 /* stop transmission and reception */ + /* after completion of any current packets */ +#define ETH_HaltImm 0x0002 /* Stop transmission and reception immediately */ +#define ETH_SwReset 0x0004 /* reset all Ethernet controller state machines */ + /* and FIFOs */ +#define ETH_FullDup 0x0008 /* allow transmission to begin while reception */ + /* is occurring */ +#define ETH_MACLoop 0x0010 /* MAC loopback */ +#define ETH_ConnM00 0x0000 /* Automatic-default */ +#define ETH_ConnM01 0x0020 /* Force 10Mbits endec */ +#define ETH_ConnM10 0x0040 /* Force MII (rate determined by MII clock */ +#define ETH_MIIOFF 0x0040 /* Force MII (rate determined by MII clock */ +#define ETH_Loop10 0x0080 /* Loop 10Mbps */ +#define ETH_MissRoll 0x0400 /* Missed error counter rolled over */ +#define ETH_MDCOFF 0x1000 /* MII Station Management Clock Off */ +#define ETH_EnMissRoll 0x2000 /* Interrupt when missed error counter rolls */ + /* over */ +#define ETH_Link10 0x8000 /* Link status 10Mbps */ + +/* CAM control register(CAMCON) */ +#define ETH_StationAcc 0x0001 /* Accept any packet with a unicast station */ + /* address */ +#define ETH_GroupAcc 0x0002 /* Accept any packet with multicast-group */ + /* station address */ +#define ETH_BroadAcc 0x0004 /* Accept any packet with a broadcast station */ + /* address */ +#define ETH_NegCAM 0x0008 /* 0: Accept packets CAM recognizes, */ + /* reject others */ + /* 1: reject packets CAM recognizes, */ + /* accept others */ +#define ETH_CompEn 0x0010 /* Compare Enable mode */ + +/* Transmit Control Register(MACTXCON) */ +#define ETH_TxEn 0x0001 /* transmit Enable */ +#define ETH_TxHalt 0x0002 /* Transmit Halt Request */ +#define ETH_NoPad 0x0004 /* suppress Padding */ +#define ETH_NoCRC 0x0008 /* Suppress CRC */ +#define ETH_FBack 0x0010 /* Fast Back-off */ +#define ETH_NoDef 0x0020 /* Disable the defer counter */ +#define ETH_SdPause 0x0040 /* Send Pause */ +#define ETH_MII10En 0x0080 /* MII 10Mbps mode enable */ +#define ETH_EnUnder 0x0100 /* Enable Underrun */ +#define ETH_EnDefer 0x0200 /* Enable Deferral */ +#define ETH_EnNCarr 0x0400 /* Enable No Carrier */ +#define ETH_EnExColl 0x0800 /* interrupt if 16 collision occur */ + /* in the same packet */ +#define ETH_EnLateColl 0x1000 /* interrupt if collision occurs after */ + /* 512 bit times(64 bytes times) */ +#define ETH_EnTxPar 0x2000 /* interrupt if the MAC transmit FIFO */ + /* has a parity error */ +#define ETH_EnComp 0x4000 /* interrupt when the MAC transmits or */ + /* discards one packet */ + +/* Transmit Status Register(MACTXSTAT) */ +#define ETH_ExColl 0x0010 /* Excessive collision */ +#define ETH_TxDeffered 0x0020 /* set if 16 collisions occur for same packet */ +#define ETH_Paused 0x0040 /* packet waited because of pause during */ + /* transmission */ +#define ETH_IntTx 0x0080 /* set if transmission of packet causes an */ + /* interrupt condiftion */ +#define ETH_Under 0x0100 /* MAC transmit FIFO becomes empty during */ + /* transmission */ +#define ETH_Defer 0x0200 /* MAC defers for MAC deferral */ +#define ETH_NCarr 0x0400 /* No carrier sense detected during the */ + /* transmission of a packet */ +#define ETH_SQE 0x0800 /* Signal Quality Error */ +#define ETH_LateColl 0x1000 /* a collision occures after 512 bit times */ +#define ETH_TxPar 0x2000 /* MAC transmit FIFO has detected a parity error */ +#define ETH_Comp 0x4000 /* MAC transmit or discards one packet */ +#define ETH_TxHalted 0x8000 /* Transmission was halted by clearing */ + /* TxEn or Halt immedite */ + +/* Receive Control Register (MACRXCON) */ +#define ETH_RxEn 0x0001 +#define ETH_RxHalt 0x0002 +#define ETH_LongEn 0x0004 +#define ETH_ShortEn 0x0008 +#define ETH_StripCRC 0x0010 +#define ETH_PassCtl 0x0020 +#define ETH_IgnoreCRC 0x0040 +#define ETH_EnAlign 0x0100 +#define ETH_EnCRCErr 0x0200 +#define ETH_EnOver 0x0400 +#define ETH_EnLongErr 0x0800 +#define ETH_EnRxPar 0x2000 +#define ETH_EnGood 0x4000 + +/* Receive Status Register(MACRXSTAT) */ +#define ETH_MCtlRecd 0x0020 +#define ETH_MIntRx 0x0040 +#define ETH_MRx10Stat 0x0080 +#define ETH_MAllignErr 0x0100 +#define ETH_MCRCErr 0x0200 +#define ETH_MOverflow 0x0400 +#define ETH_MLongErr 0x0800 +#define ETH_MRxPar 0x2000 +#define ETH_MRxGood 0x4000 +#define ETH_MRxHalted 0x8000 + +/* Tx Frame Descriptor Options */ +#define TX_OptNoPadding (0x01) +#define TX_OptNoCRCMode (0x02) +#define TX_OptMACTxIntEn (0x04) +#define TX_OptLittleEndian (0x08) +#define TX_OptFrameDataPtrInc (0x10) +#define TX_OptWA01 (0x20) +#define TX_OptWA10 (0x40) +#define TX_OptWA11 (0x60) + +/* bit field for frame data pointer word */ +typedef struct __BF_FrameDataPtr { + u32 dataPtr:31; + u32 owner: 1; +} BF_FrameDataPtr; + +typedef union _FrameDataPtr { + u32 ui; + BF_FrameDataPtr bf; +} FrameDataPtr; + +typedef struct __BF_TX_Options { + u32 no_padding: 1; + u32 no_crc: 1; + u32 macTxIrqEnbl: 1; + u32 littleEndian: 1; + u32 frameDataDir: 1; + u32 widgetAlign: 2; + u32 reserved:25; +} BF_TX_Options; + +typedef union _TX_Options { + u32 ui; + BF_TX_Options bf; +} TX_Options; + +typedef struct __BF_RX_Status { + u32 len:16; /* frame length */ + u32 reserved1: 3; + u32 overMax: 1; + u32 reserved2: 1; + u32 ctrlRcv: 1; + u32 intRx: 1; + u32 rx10stat: 1; + u32 alignErr: 1; + u32 crcErr: 1; + u32 overFlow: 1; + u32 longErr: 1; + u32 reserved3: 1; + u32 parityErr: 1; + u32 good: 1; + u32 halted: 1; +} BF_RX_Status; + +typedef union _RX_Status { + u32 ui; + BF_RX_Status bf; +} RX_Status; + +typedef struct __BF_TX_Status { + u32 len:16; /* frame length */ + u32 txCollCnt: 4; + u32 exColl: 1; + u32 txDefer: 1; + u32 paused: 1; + u32 intTx: 1; + u32 underRun: 1; + u32 defer: 1; + u32 noCarrier: 1; + u32 SQErr: 1; + u32 lateColl: 1; + u32 parityErr: 1; + u32 complete: 1; + u32 halted: 1; +} BF_TX_Status; + +typedef union _TX_Status { + u32 ui; + BF_TX_Status bf; +} TX_Status; + +/* TX descriptor structure */ +typedef struct __TX_FrameDescriptor { + volatile FrameDataPtr m_frameDataPtr; + volatile TX_Options m_opt; + volatile TX_Status m_status; + volatile struct __TX_FrameDescriptor *m_nextFD; + /* We can add our own "per frame" data here */ + struct sk_buff *skb; +} TX_FrameDesc; + +/* RX descriptor structure */ +typedef struct __RX_FrameDescriptor { + volatile FrameDataPtr m_frameDataPtr; + volatile u32 m_reserved; + volatile RX_Status m_status; + volatile struct __RX_FrameDescriptor *m_nextFD; + /* We can add our own "per frame" data here */ + struct sk_buff *skb; +} RX_FrameDesc; + +/* ETH Frame Structure */ +typedef struct __ETHFrame { + u8 m_dstAddr[ETH_ALEN] __packed; + u8 m_srcAddr[ETH_ALEN] __packed; + u16 m_proto __packed; + u8 m_payload[ETH_DATA_LEN] __packed; +} ETHFrame; + +#endif diff --git a/drivers/net/arm/p2001_eth.c b/drivers/net/arm/p2001_eth.c new file mode 100644 index 00000000..fa5e976e --- /dev/null +++ b/drivers/net/arm/p2001_eth.c @@ -0,0 +1,934 @@ +/* + * linux/drivers/char/p2001_eth.c + * + * Driver for P2001 ethernet unit + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 + */ + +/* + * Version 1.0: First working version + * Version 1.1: mdio ioctl calls + * Version 1.2: statistics counter + * Version 1.3: skbuff direct instead of buffer-copy for sending + * Version 1.4: ethtool calls + * Version 1.5: interrupt driven transmit with transmit buffer ring + * Version 1.6: support for all interfaces with phy connected + * Version 1.7: generic mii infrastructure + * Version 1.8: automatic MDIO CLK calculation + * Version 1.9: added request_mem_region + * Version 1.10: bug fix for main isp + * Version 1.11: removed all READ_REG/WRITE_REG + * Version 1.12: transmit timeout, no boot via eth1 + * Version 1.13: initialisation fix, which results in transmission errors, + * some pings are 10 times longer than the regular ones (glitches) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Processor type for cache alignment. */ +#include +#include +#include /* User space memory access functions */ + + + +/************************************************************************** + * Definitions + **************************************************************************/ +static const char *version = + "p2001_eth.c:v1.13 10/13/2004 Tobias Lorenz (tobias.lorenz@gmx.net)\n"; + +static const char p2001_eth_name[] = "P2001 eth"; + +/* Hardware lookup table */ +struct { + unsigned int nr; /* ethernet unit number / dma channel number */ + unsigned int base_addr; /* device I/O address */ + unsigned int irq; /* device data IRQ number (error IRQ +1) */ + unsigned int phy_id; /* assigned phy address */ + unsigned char mac_hw_addr[6]; /* fixed MAC address */ +} p2001_eth_dev_list[4] = { + { 0, (unsigned int)P2001_EU0, IRQ_EU0_DATA, 0, {0x00,0x09,0x4F,0x00,0x00,0x02} }, + { 1, (unsigned int)P2001_EU1, IRQ_EU1_DATA, 1, {0x00,0x09,0x4F,0x00,0x00,0x03} }, + { 2, (unsigned int)P2001_EU2, IRQ_EU2_DATA, 2, {0x00,0x09,0x4F,0x00,0x00,0x04} }, + { 3, (unsigned int)P2001_EU3, IRQ_EU3_DATA, 3, {0x00,0x09,0x4F,0x00,0x00,0x05} }, +}; + +/* DMA descriptions and buffers */ +#define NUM_RX_DESC 16 /* Number of RX descriptor registers. */ +#define NUM_TX_DESC 16 /* Number of TX descriptor registers. */ +#define DMA_BUF_SIZE 2048 /* Buffer size */ + +/* Drivers private structure */ +struct p2001_eth_private { + struct net_device_stats stats; + + /* DMA descriptors and buffers */ + DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((aligned(16))); + DMA_DSC txd[NUM_TX_DESC] __attribute__ ((aligned(16))); + char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((aligned(16))); + struct sk_buff *txb[NUM_TX_DESC]; + /* producer/comsumer pointers for Tx/Rx ring */ + int cur_tx, dirty_tx; + int cur_rx, dirty_rx; + + /* Device selectors */ + unsigned int nr; /* NR/DMA channel: 0..3 */ + char adapter_name[11]; /* P2001 ethx\0 */ + + spinlock_t lock; + + /* The Tx queue is full. */ + unsigned int tx_full; + + /* MII interface info */ + struct mii_if_info mii; +}; + +/* mdio handling */ +static void mdio_hard_reset(void); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int val); + +/* net_device functions */ +static struct net_device_stats * p2001_eth_get_stats(struct net_device *dev); +static int p2001_eth_open(struct net_device *dev); +static int p2001_eth_stop(struct net_device *dev); +static int p2001_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void p2001_eth_tx_timeout(struct net_device *dev); +static int p2001_eth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +/* interrupt routines */ +static irqreturn_t p2001_eth_data_interrupt(int irq, struct net_device *dev, struct pt_regs *regs); +static irqreturn_t p2001_eth_error_interrupt(int irq, struct net_device *dev, struct pt_regs *regs); + +/* ethtool ops */ +static struct ethtool_ops p2001_eth_ethtool_ops; + +/* driver functions (pci_driver, isa_driver) */ +struct net_device * __init p2001_eth_probe(int unit); +static void __devexit p2001_eth_remove(struct net_device *dev); + + + +/************************************************************************** + * PHY MANAGEMENT UNIT - Read/write + **************************************************************************/ + +/** + * mdio_hard_reset - hardware reset all MII PHYs and set MDIO CLK + */ +static void mdio_hard_reset() +{ + /* GPIO24/25: TX_ER2/TX_ER0 */ + /* GPIO26/27: PHY_RESET/TX_ER1 */ + P2001_GPIO->PIN_MUX |= 0x0018; + // 31-16: 0000 1111 0000 0000 + P2001_GPIO->GPIO2_En |= 0x0400; + + P2001_GPIO->GPIO2_Out |= 0x04000000; + P2001_GPIO->GPIO2_Out &= ~0x0400; + mdelay(500); + P2001_GPIO->GPIO2_Out |= 0x0400; + + /* set management unit clock divisor */ + // max. MDIO CLK = 2.048 MHz (EU.doc) + // max. MDIO CLK = 8.000 MHz (LXT971A) + // sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz + // n >= sysclk/4.096 MHz - 1 + P2001_MU->MU_DIV = (CONFIG_SYSCLK/4096000)-1; // 2.048 MHz + //asm("nop \n nop"); +} + + +/** + * mdio_read - read MII PHY register + * @dev: the net device to read + * @regadr: the phy register id to read + * + * Read MII registers through MDIO and MDC + * using MDIO management frame structure and protocol(defined by ISO/IEC). + */ +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + do { + /* Warten bis Hardware inaktiv (MIU = "0") */ + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); + + /* Schreiben MU_CNTL */ + P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<10); + + /* Warten bis Hardware aktiv (MIU = "1") */ + while ((P2001_MU->MU_CNTL & 0x8000) == 0) + barrier(); + //asm("nop \r\n nop"); + + /* Warten bis Hardware inaktiv (MIU = "0") */ + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); + + /* Fehler, wenn MDIO Read Error (MRE = "1") */ + } while (P2001_MU->MU_CNTL & 0x4000); + + /* Lesen MU_DATA */ + return P2001_MU->MU_DATA; +} + + +/** + * mdio_write - write MII PHY register + * @dev: the net device to write + * @regadr: the phy regiester id to write + * @value: the register value to write with + * + * Write MII registers with @value through MDIO and MDC + * using MDIO management frame structure and protocol(defined by ISO/IEC) + */ +static void mdio_write(struct net_device *dev, int phy_id, int location, int val) +{ + /* Warten bis Hardware inaktiv (MIU = "0") */ + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); + + /* Schreiben MU_DATA */ + P2001_MU->MU_DATA = val; + + /* Schreiben MU_CNTL */ + P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10); + + /* Warten bis Hardware aktiv (MIU = "1") */ + while ((P2001_MU->MU_CNTL & 0x8000) == 0) + barrier(); + //asm("nop \r\n nop"); + + /* Warten bis Hardware inaktiv (MIU = "0") */ + while (P2001_MU->MU_CNTL & 0x8000) + barrier(); +} + + +// mdio_write(dev, priv->mii.phy_id, MII_BMCR, BMCR_RESET); + + + +/************************************************************************** + * GET_STATS - Get read/write statistics + **************************************************************************/ + +/** + * p2001_eth_get_stats - Get p2001 read/write statistics + * @dev: the net device to get statistics for + * + * get tx/rx statistics for p2001 + */ +static struct net_device_stats * p2001_eth_get_stats(struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + + return &priv->stats; +} + + + +/************************************************************************** + * OPEN - Open network device + **************************************************************************/ + +/** + * p2001_eth_open - open p2001 ethernet device + * @dev: the net device to open + * + * Do some initialization and start net interface. + * enable interrupts and set timer. + */ +static int p2001_eth_open(struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + int i, ret; + +// printk("%s: p2001_eth_open\n", dev->name); + + /* request data and error interrupts */ + ret = request_irq(dev->irq, (void *) &p2001_eth_data_interrupt, 0, dev->name, dev); + if (ret) + return ret; + ret = request_irq(dev->irq+1, (void *) &p2001_eth_error_interrupt, 0, dev->name, dev); + if (ret) + return ret; + + /* set rx filter (physical mac address) */ + EU->RMAC_PHYU = + (dev->dev_addr[0]<< 8) + + (dev->dev_addr[1]<< 0); + EU->RMAC_PHYL = + (dev->dev_addr[2]<<24) + + (dev->dev_addr[3]<<16) + + (dev->dev_addr[4]<<8 ) + + (dev->dev_addr[5]<<0 ); + + /* initialize the tx descriptor ring */ + priv->tx_full = 0; + priv->cur_tx = 0; + priv->dirty_tx = 0; + for (i = 0; i < NUM_TX_DESC; i++) { + priv->txd[i].stat = 0; // DSC0 + priv->txd[i].cntl = 0; // DSC1 + priv->txd[i].buf = 0; // DSC2 BUFFER (EU-TX data) + priv->txd[i].next = &priv->txd[(i+1) % NUM_TX_DESC]; // DSC3 NEXTDSC @next/@first + } + EU->TMAC_DMA_DESC = &priv->txd[0]; + + /* initialize the rx descriptor ring */ + priv->cur_rx = 0; + priv->dirty_rx = 0; + for (i = 0; i < NUM_RX_DESC; i++) { + priv->rxd[i].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END + priv->rxd[i].cntl = (1<<30) | (1<<23); // DSC1 INT|RECEIVE + priv->rxd[i].cntl |= priv->nr << 16; // DSC1 CHANNEL + priv->rxd[i].cntl |= DMA_BUF_SIZE; // DSC1 LEN + priv->rxd[i].buf = &priv->rxb[i*DMA_BUF_SIZE]; // DSC2 BUFFER (EU-RX data) + priv->rxd[i].next = &priv->rxd[(i+1) % NUM_RX_DESC]; // DSC3 NEXTDSC @next/@first + } + EU->RMAC_DMA_DESC = &priv->rxd[0]; + + /* set transmitter mode */ + EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */ + //(1<<3) | /* CSI: Carrier Sense ignore */ + (1<<2); /* ATP: Automatic Transmit Padding */ + + /* set receive mode */ + EU->RMAC_CNTL = (1<<3) | /* BROAD: Broadcast packets */ + (1<<1); /* PHY : Packets to out MAC address */ + + /* enable receiver */ + EU->RMAC_DMA_EN = 1; + + netif_start_queue(dev); + + return 0; +} + + + +/************************************************************************** + * STOP - Close network device + **************************************************************************/ + +/** + * p2001_eth_stop - close p2001 ethernet device + * @dev: the net device to be closed + * + * Disable interrupts, stop the Tx and Rx Status Machine + * free Tx and RX socket buffer + */ +static int p2001_eth_stop(struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + struct sk_buff *skb; + unsigned int i; + +// printk("%s: p2001_eth_stop\n", dev->name); + + netif_stop_queue(dev); + + /* Stop the chip's Tx and Rx Status Machine */ + EU->TMAC_DMA_EN = 0; + EU->RMAC_DMA_EN = 0; + + free_irq(dev->irq, dev); + free_irq(dev->irq+1, dev); + + /* Free Tx skbuff */ + for (i = 0; i < NUM_TX_DESC; i++) { + skb = priv->txb[i]; + if (skb) { + dev_kfree_skb(skb); + priv->txb[i] = 0; + } + } + + + /* Green! Put the chip in low-power mode. */ + + return 0; +} + + + +/************************************************************************** + * HARD START XMIT - Force start sending packets + **************************************************************************/ + +/** + * p2001_eth_hard_start_xmit - start transmit routine + * @skb: socket buffer pointer to put the data being transmitted + * @dev: the net device to transmit with + * + * Set the transmit buffer descriptor, + * and write TxENA to enable transmit state machine. + * tell upper layer if the buffer is full + */ +static int p2001_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + unsigned int entry; + unsigned long flags; + unsigned int index_cur_tx, index_dirty_tx; + unsigned int count_dirty_tx; + + spin_lock_irqsave(&priv->lock, flags); + EU->TMAC_DMA_EN = 0; /* clear run bit */ + +// printk("%s: p2001_eth_hard_start_xmit: size=%d\n", dev->name, skb->len); + + /* Calculate the next Tx descriptor entry. */ + entry = priv->cur_tx % NUM_TX_DESC; + priv->txb[entry] = skb; + + /* set the transmit buffer descriptor and enable Transmit State Machine */ + priv->txd[entry].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END + priv->txd[entry].cntl = priv->nr << 16; // DSC1 CHANNEL + priv->txd[entry].cntl |= (1<<30); // DSC1 INT + priv->txd[entry].cntl |= skb->len; // DSC1 LEN + priv->txd[entry].buf = skb->data; // DSC2 BUFFER (EU-TX data) + + priv->cur_tx++; + index_cur_tx = priv->cur_tx; + index_dirty_tx = priv->dirty_tx; + + for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; index_dirty_tx++) + count_dirty_tx++; + +// printk("%s: entry=%d, cur_tx=%d, dirty_tx=%d, count_dirty_tx=%d\n", dev->name, +// entry, priv->cur_tx % NUM_TX_DESC, priv->dirty_tx % NUM_TX_DESC, count_dirty_tx); + + EU->TMAC_DMA_DESC = &priv->txd[priv->dirty_tx % NUM_TX_DESC]; + + EU->TMAC_DMA_EN = 1; /* set run bit */ + spin_unlock_irqrestore(&priv->lock, flags); + + dev->trans_start = jiffies; + +// printk(KERN_INFO "%s: Queued Tx packet at %p size %d to slot %d.\n", +// dev->name, skb->data, (int)skb->len, entry); + + return 0; +} + + + +/************************************************************************** + * DO_IOCTL - Process MII i/o control command + **************************************************************************/ + +/** + * p2001_eth_do_ioctl - process MII i/o control command + * @dev: the net device to command for + * @rq: parameter for command + * @cmd: the i/o command + * + * Process MII command like read/write MII register + */ +static int p2001_eth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct p2001_eth_private *priv = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + + return generic_mii_ioctl(&priv->mii, data, cmd, NULL); +} + + + +/************************************************************************** + * TX_TIMEOUT - Transmit timeout routine + **************************************************************************/ + +/** + * p2001_eth_tx_timeout - transmit timeout routine + * @dev: the net device to command for + * + * print transmit timeout status + * disable interrupts and do some tasks + */ +static void p2001_eth_tx_timeout(struct net_device *dev) +{ +// struct p2001_eth_private *priv = dev->priv; + + printk(KERN_INFO "%s: Transmit timeout\n", dev->name); +} + + + +/************************************************************************** + * TX - interrupt transmit routine + **************************************************************************/ + +/** + * p2001_eth_tx - finish up transmission of packets + * @net_dev: the net device to be transmitted on + * + * Check for error condition and free socket buffer etc + * schedule for more transmission as needed + * Note: This fucntion is called by interrupt handler, + * don't do "too much" work here + */ + +static void p2001_eth_tx(struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + unsigned int index_cur_tx, index_dirty_tx; + unsigned int count_dirty_tx; + +// printk("%s: p2001_eth_tx\n", dev->name); + for (; priv->dirty_tx != priv->cur_tx; priv->dirty_tx++) { + struct sk_buff *skb; + unsigned int entry; + unsigned int status; + + entry = priv->dirty_tx % NUM_TX_DESC; + status = priv->txd[entry].stat; + + if (status & (1<<31)) { // OWN + /* The packet is not transmitted yet (owned by hardware) ! + Note: the interrupt is generated only when Tx Machine + is idle, so this is an almost impossible case */ +// printk("%s: p2001_eth_tx: nothing more to do\n", dev->name); + break; + } + +// if (status & 0x0000000f) { // CRS|ED|OWC|EC + if (status & 0x00000007) { // ED|OWC|EC + /* packet unsuccessfully transmitted */ + printk("%s: Transmit error, Tx status %8.8x.\n", dev->name, status); + priv->stats.tx_errors++; +// if (status & (1<<3)) // CRS +// priv->stats.tx_carrier_errors++; + if (status & (1<<1)) // OWC + priv->stats.tx_window_errors++; + } else { + /* packet successfully transmitted */ +// printk("%s: p2001_eth_tx: success\n", dev->name); + priv->stats.collisions += (status & 0x00000f00) >> 8; + priv->stats.tx_bytes += priv->txd[entry].cntl & 0xffff; + priv->stats.tx_packets++; + } + /* Free the original skb. */ + skb = priv->txb[entry]; + dev_kfree_skb_irq(skb); + priv->txb[entry] = 0; + priv->txd[entry].stat = 0; // DSC0 + priv->txd[entry].cntl = 0; // DSC1 + priv->txd[entry].buf = 0; // DSC2 BUFFER (EU-TX data) + } + + if (priv->tx_full && netif_queue_stopped(dev)) { + index_cur_tx = priv->cur_tx; + index_dirty_tx = priv->dirty_tx; + + for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; index_dirty_tx++) + count_dirty_tx++; + + if (count_dirty_tx < NUM_TX_DESC - 4) { + /* The ring is no longer full, clear tx_full and + schedule more transmissions by netif_wake_queue(dev) */ + priv->tx_full = 0; + netif_wake_queue(dev); + } + } + + EU->TMAC_DMA_STAT |= (1<<8); +} + + + +/************************************************************************** + * RX - interrupt receive routine + **************************************************************************/ + +/** + * p2001_eth_rx - p2001_eth receive routine + * @dev: the net device which receives data + * + * Process receive interrupt events, + * put buffer to higher layer and refill buffer pool + * Note: This fucntion is called by interrupt handler, + * don't do "too much" work here + */ +static void p2001_eth_rx(struct net_device *dev) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + unsigned int entry; + unsigned int status; + struct sk_buff *skb; + unsigned int pkt_len; + +// printk("%s: p2001_eth_rx\n", dev->name); + while(1) { + entry = priv->cur_rx % NUM_RX_DESC; + status = priv->rxd[entry].stat; + if (status & (1<<31)) + break; + + if (status & 0x07c00000) { // NOBYTE|CRCERR|COL|ISE|ILEN + /* corrupted packet received */ + printk(KERN_INFO "%s: Corrupted packet " + "received, buffer status = 0x%8.8x.\n", + dev->name, status); + priv->stats.rx_errors++; + } else { + /* give the socket buffer to the upper layers */ + pkt_len = priv->rxd[entry].cntl & 0xffff; + skb = dev_alloc_skb(pkt_len); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + break; + } + + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP fields. */ + + eth_copy_and_sum(skb, priv->rxd[entry].buf, pkt_len, 0); + skb_put(skb, pkt_len); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + /* some network statistics */ + dev->last_rx = jiffies; + priv->stats.rx_bytes += pkt_len; + priv->stats.rx_packets++; + } + + /* disable receiver */ + // FIXME: is that ok? it can produce grave errors. + EU->RMAC_DMA_EN = 0; /* clear run bit */ + EU->RMAC_DMA_STAT = EU->RMAC_DMA_STAT; + + /* return the descriptor and buffer to receive ring */ + priv->rxd[entry].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END + priv->rxd[entry].cntl = (1<<30) | (1<<23); // DSC1 INT|RECEIVE + priv->rxd[entry].cntl |= priv->nr << 16; // DSC1 CHANNEL + priv->rxd[entry].cntl |= DMA_BUF_SIZE; // DSC1 LEN + + /* enable receiver */ + EU->RMAC_DMA_EN = 0x01; /* set run bit */ + + priv->cur_rx++; + } +} + + + +/************************************************************************** + * INTERRUPT - Interrupt routines + **************************************************************************/ + +/** + * p2001_eth_data_interrupt - p2001_eth data interrupt handler + * @irq: the irq number + * @dev: the client data object + * @regs: snapshot of processor context + * + * The interrupt handler does all of the Rx thread work, + * and cleans up after the Tx thread + */ +static irqreturn_t p2001_eth_data_interrupt(int irq, struct net_device *dev, struct pt_regs *regs) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + int boguscnt = 10; // max_interrupt_work + unsigned int handled = 0; + unsigned int rx_status; + unsigned int tx_status; + +// printk("%s: p2001_eth_data_interrupt: start\n", dev->name); + + spin_lock(&priv->lock); + + do { + /* Rx interrupt */ + rx_status = EU->RMAC_DMA_STAT; + if (rx_status & (1<<8)) { + // usally there is only one interrupt for multiple receives + p2001_eth_rx(dev); + handled = 1; + } + + /* Tx interrupt */ + tx_status = EU->TMAC_DMA_STAT; + if (tx_status & (1<<8)) { + // usally there is only one interrupt for multiple transmits + p2001_eth_tx(dev); + handled = 1; + } + } while (--boguscnt && ((rx_status & (1<<8)) | (tx_status & (1<<8)))); + + if (!handled) { + printk(KERN_INFO "%s: p2001_eth_data_interrupt: interrupt not handled\n", + dev->name); + printk(KERN_INFO "%s: p2001_eth_data_interrupt: (rx=%#8.8x tx=%#8.8x)\n", + dev->name, rx_status, tx_status); + handled = 1; + } + + spin_unlock(&priv->lock); + return IRQ_RETVAL(handled); +} + + +/** + * p2001_eth_error_interrupt - p2001_eth error interrupt handler + * @irq: the irq number + * @dev: the client data object + * @regs: snapshot of processor context + * + * The interrupt handler does all error tasks + */ +static irqreturn_t p2001_eth_error_interrupt(int irq, struct net_device *dev, struct pt_regs *regs) +{ + struct p2001_eth_private *priv = dev->priv; + P2001_ETH_regs_ptr EU = (P2001_ETH_regs_ptr) dev->base_addr; + unsigned int handled = 1; + + spin_lock(&priv->lock); + if (EU->RMAC_DMA_STAT) { + printk("%s: p2001_eth_error_interrupt: rmac_dma_stat=%#8.8x\n", dev->name, EU->RMAC_DMA_STAT); + EU->RMAC_DMA_STAT |= (1<<7); + } + if (EU->TMAC_DMA_STAT) { + printk("%s: p2001_eth_error_interrupt: tmac_dma_stat=%#8.8x\n", dev->name, EU->TMAC_DMA_STAT); + EU->TMAC_DMA_STAT |= (1<<7); + } + spin_unlock(&priv->lock); + return IRQ_RETVAL(handled); +} + + + +/************************************************************************** + * PROBE - Look for an adapter, this routine's visible to the outside + **************************************************************************/ + +/** + * p2001_eth_probe - Probe for p2001 ethernet device + * @unit: the p2001 ethernet unit number + * + * Check and probe for p2001 net device. + * Get mac address and assign p2001-specific entries in the device structure. + */ +struct net_device * __init p2001_eth_probe(int unit) +{ + struct net_device *dev; + struct p2001_eth_private *priv; + int i, err; + + dev = alloc_etherdev(sizeof(struct p2001_eth_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + SET_MODULE_OWNER(dev); + + /* Configure unit specific variables */ + priv = dev->priv; + dev->base_addr = p2001_eth_dev_list[unit].base_addr; + dev->irq = p2001_eth_dev_list[unit].irq; + priv->nr = p2001_eth_dev_list[unit].nr; + sprintf(priv->adapter_name, "%s%i", p2001_eth_name, unit); + request_mem_region(dev->base_addr, 0x1000, priv->adapter_name); + spin_lock_init(&priv->lock); + + /* The p2001_eth-specific entries in the device structure. */ + // init + dev->get_stats = &p2001_eth_get_stats; + // get_wireless_stats + dev->ethtool_ops = &p2001_eth_ethtool_ops; + // uninit + // destructor + dev->open = &p2001_eth_open; + dev->stop = &p2001_eth_stop; + dev->hard_start_xmit = &p2001_eth_hard_start_xmit; + // poll + // hard_header + // rebuild_header + // set_multicast_list + // set_mac_address + dev->do_ioctl = &p2001_eth_do_ioctl; + // set_config + // hard_header_cache + // header_cache_update + // change_mtu + dev->tx_timeout = &p2001_eth_tx_timeout; + // vlan_rx_register + // vlan_rx_add_vid + // vlan_rx_kill_vid + // hard_header_parse + // neigh_setup + // accept_fastpath + // poll_controller + // last_stats + ether_setup(dev); + + err = register_netdev(dev); + if (err) + goto err_out; +// printk("%s: p2001_eth_probe\n", dev->name); + + /* Set MAC filter */ + memcpy(dev->dev_addr, p2001_eth_dev_list[unit].mac_hw_addr, ETH_ALEN); + //random_ether_addr(dev->dev_addr); + + /* MII setup */ + priv->mii.phy_id = p2001_eth_dev_list[unit].phy_id; + priv->mii.phy_id_mask = 0x1F; + priv->mii.reg_num_mask = 0x1F; + priv->mii.dev = dev; + priv->mii.mdio_read = mdio_read; + priv->mii.mdio_write = mdio_write; + + /* print some information about our NIC */ + printk(KERN_INFO "%s: ADDR %#lx, IRQ %d/%d, MAC ", dev->name, dev->base_addr, dev->irq, dev->irq+1); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + + printk(KERN_INFO "%s: phy_addr = %d\n", dev->name, priv->mii.phy_id); + printk(KERN_INFO "%s: phy ID = 0x%08x\n", dev->name, + (mdio_read(dev, priv->mii.phy_id, MII_PHYSID2) << 16) | + mdio_read(dev, priv->mii.phy_id, MII_PHYSID1)); + + netif_carrier_on(dev); + + return dev; + +//err_out_unregister: +// unregister_netdev(dev); +err_out: + release_mem_region(dev->base_addr, 0x1000); + free_netdev(dev); + return ERR_PTR(err); +} + + + +/************************************************************************** + * REMOVE - Remove an adapter, this routine's visible to the outside + **************************************************************************/ + +static void __devexit p2001_eth_remove(struct net_device *dev) +{ +// printk("%s: p2001_eth_remove\n", dev->name); +} + + + +/************************************************************************** + * GET_DRVINFO - Return information about driver + **************************************************************************/ + +/** + * p2001_eth_get_drvinfo - Return information about driver + * @dev: the net device to probe + * @info: container for info returned + * + * Process ethtool command such as "ethtool -i" to show information + */ +static void p2001_eth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, p2001_eth_name); + strcpy(info->version, version); + sprintf(info->bus_info, "ADDR 0x%lx", dev->base_addr); +} + +static struct ethtool_ops p2001_eth_ethtool_ops = { + .get_drvinfo = p2001_eth_get_drvinfo, +}; + + + +/************************************************************************** + * Module functions + **************************************************************************/ +static struct net_device *p2001_eth_dev[4]; + +/** + * init_module: + * + * When the driver is loaded as a module this function is called. We fake up + * a device structure with the base I/O and interrupt set as if it were being + * called from Space.c. This minimises the extra code that would otherwise + * be required. + * + * Returns 0 for success or -EIO if a card is not found. Returning an error + * here also causes the module to be unloaded + */ +static int __init p2001_eth_init_module(void) +{ + int i; + +// printk("p2001_eth_init_module\n"); + printk(version); + mdio_hard_reset(); + +// for (i = 0; i < 4; i++) { + for (i = 0; i < 2; i++) { + p2001_eth_dev[i] = p2001_eth_probe(i); + if (!p2001_eth_dev[i]) + return (unsigned int)p2001_eth_dev[i]; + } + + return 0; +} + + +/** + * cleanup_module: + * + * The module is being unloaded. We unhook our network device from the system + * and then free up the resources we took when the card was found. + */ +static void __exit p2001_eth_cleanup_module(void) +{ +// printk("p2001_eth_cleanup_module\n"); +} + +module_init(p2001_eth_init_module); +module_exit(p2001_eth_cleanup_module); + +MODULE_AUTHOR("Tobias Lorenz"); +MODULE_DESCRIPTION("P2001 ethernet unit driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 4ffc9b44..6c152a3f 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -81,9 +81,23 @@ : Make `version[]' __initdata : Uninlined the read/write reg/word functions. + Craig Peacock : Apr 2001 - Craig.Peacock@senet.com.au + Tom Walsh : May 2001 - tom@openhardware.net + David McCullough : Jun 2001 - davidm@snapgear.com + : Customized for use on uClinux & MC68EZ328 platforms. + + Evan Stawnyczy : Customized for use on MC68VZ328 platform. + + Daniel Potts : uClinux sleep support, ucDimm + Mark McChrystal : uClinux sleep support, ucSimm + Oskar Schirmer : oskar@scara.com : HiCO.SH4 (superh) support added (irq#1, cs89x0_media=) + Craig Hackney : Added support for Triscend A7S. + + Georges Menie : Jan 2004 - reworked uClinux support + Deepak Saxena : dsaxena@plexity.net : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support @@ -147,13 +161,20 @@ #include #include +#include +#ifdef CONFIG_CS89x0_SWAPPED +#include +#else #include +#endif #include #if ALLOW_DMA #include #endif +#include #include "cs89x0.h" +#include "cs89x0_defs.h" static char version[] __initdata = "cs89x0.c: v2.4.3-pre1 Russell Nelson , Andrew Morton \n"; @@ -171,7 +192,12 @@ static char version[] __initdata = /* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps them to system IRQ numbers. This mapping is card specific and is set to the configuration of the Cirrus Eval board for this chip. */ -#ifdef CONFIG_ARCH_CLPS7500 +#if defined(_CS89X0_DEFS_EMBED_) +/* ioaddr and irq for embedded boards are set in specific setup hook */ +static unsigned int netcard_portlist[] __initdata = { 0 }; +#elif defined(CONFIG_ALMA_ANS) +static unsigned int netcard_portlist[] __initdata = { 0x10200300, 0 }; +#elif defined(CONFIG_ARCH_CLPS7500) static unsigned int netcard_portlist[] __initdata = { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; static unsigned int cs8900_irq_map[] = {12,0,0,0}; @@ -256,8 +282,17 @@ static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); static void reset_chip(struct net_device *dev); +static int set_mac_address(struct net_device *dev, void *addr); +static void count_rx_errors(int status, struct net_local *lp); +static void write_irq(struct net_device *dev, int chip_type, int irq); +static int readreg(struct net_device *dev, int portno); +static void writereg(struct net_device *dev, int portno, int value); +static int readword(struct net_device *dev, int portno); +static void writeword(struct net_device *dev, int portno, int value); +#ifndef NO_EPROM static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer); static int get_eeprom_cksum(int off, int len, int *buffer); +#endif static int set_mac_address(struct net_device *dev, void *addr); static void count_rx_errors(int status, struct net_local *lp); #ifdef CONFIG_NET_POLL_CONTROLLER @@ -268,6 +303,8 @@ static void get_dma_channel(struct net_device *dev); static void release_dma_buff(struct net_local *lp); #endif +#include "cs89x0_fct.h" + /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -286,6 +323,10 @@ static int __init dma_fn(char *str) __setup("cs89x0_dma=", dma_fn); #endif /* !defined(MODULE) && (ALLOW_DMA != 0) */ +#ifdef CONFIG_PM +static int cs89x0_in_use = 0; +#endif + #ifndef MODULE static int g_cs89x0_media__force; @@ -321,6 +362,14 @@ struct net_device * __init cs89x0_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); + +#ifdef HW_INIT_HOOK + if (cs89x_hw_init_hook(dev, unit) != 0) { + free_netdev(dev); + return ERR_PTR(-ENODEV); + } +#endif + io = dev->base_addr; irq = dev->irq; @@ -442,6 +491,7 @@ writereg(struct net_device *dev, u16 regno, u16 value) writeword(dev->base_addr, DATA_PORT, value); } +#ifndef NO_EPROM static int __init wait_eeprom_ready(struct net_device *dev) { @@ -486,6 +536,7 @@ get_eeprom_cksum(int off, int len, int *buffer) return 0; return -1; } +#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* @@ -511,11 +562,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { struct net_local *lp = netdev_priv(dev); static unsigned version_printed; - int i; + int i, retval; int tmp; unsigned rev_type = 0; +#ifndef NO_EPROM int eeprom_buff[CHKSUM_LEN]; - int retval; +#endif SET_MODULE_OWNER(dev); /* Initialize the device structure. */ @@ -558,6 +610,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) readreg(dev, 0); #endif +#ifndef NO_REQUEST_REGION /* Grab the region so we can find another board if autoIRQ fails. */ /* WTF is going on here? */ if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) { @@ -566,6 +619,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) retval = -EBUSY; goto out1; } +#else + if (0) + goto out1; /* to suppress warning */ +#endif /* NO_REQUEST_REGION */ #ifdef CONFIG_SH_HICOSH4 /* truely reset the chip */ @@ -613,11 +670,16 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) /* Check the chip type and revision in order to set the correct send command CS8920 revision C and CS8900 revision F can use the faster send. */ +#ifndef USE_TX_AFTER_ALL lp->send_cmd = TX_AFTER_381; if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') lp->send_cmd = TX_NOW; if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') lp->send_cmd = TX_NOW; +#else + /* some board have trouble keeping up */ + lp->send_cmd = TX_AFTER_ALL; +#endif if (net_debug && version_printed++ == 0) printk(version); @@ -630,7 +692,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) dev->base_addr); reset_chip(dev); - + +#ifndef NO_EPROM /* Here we read the current configuration of the chip. If there is no Extended EEPROM then the idea is to not disturb the chip configuration, it should have been correctly setup by automatic @@ -761,6 +824,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n", dev->name, lp->adapter_cnf); } +#else /* NO_EPROM */ + printk("\n"); + /* Fill this in, we don't have an EEPROM */ + lp->adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T; + lp->auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT; +#endif /* NO_EPROM */ /* allow them to force multiple transceivers. If they force multiple, autosense */ { @@ -792,6 +861,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) lp->irq_map = 0xffff; +#ifndef MONO_IRQ_MAP /* If this is a CS8900 then no pnp soft */ if (lp->chip_type != CS8900 && /* Check if the ISA IRQ has been set */ @@ -826,6 +896,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (!dev->irq) dev->irq = i; } +#endif printk(" IRQ %d", dev->irq); @@ -1042,6 +1113,9 @@ void __init reset_chip(struct net_device *dev) writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); +#ifdef CONFIG_ARCH_TA7S + a7hal_lancs8900_reset( 0 ); +#endif /* wait 30 ms */ msleep(30); @@ -1057,6 +1131,12 @@ void __init reset_chip(struct net_device *dev) outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } #endif /* IXDP2x01 */ +#ifdef CONFIG_EXCALIBUR +/* This is a hack that seems to be necessary for the 2.0 nios core + * that must be done after power up resets. + */ + *(char *)dev->base_addr = 0; +#endif /* Wait until the chip is reset */ reset_start_time = jiffies; @@ -1244,6 +1324,7 @@ detect_bnc(struct net_device *dev) static void write_irq(struct net_device *dev, int chip_type, int irq) { +#ifndef MONO_IRQ_MAP int i; if (chip_type == CS8900) { @@ -1258,6 +1339,9 @@ write_irq(struct net_device *dev, int chip_type, int irq) } else { writereg(dev, PP_CS8920_ISAINT, irq); } +#else + writereg(dev, PP_CS8900_ISAINT, 0); +#endif } /* Open/initialize the board. This is called (in the current kernel) @@ -1278,6 +1362,7 @@ net_open(struct net_device *dev) int i; int ret; +#ifndef MONO_IRQ_MAP #if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */ if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ @@ -1332,6 +1417,10 @@ net_open(struct net_device *dev) } } +#else /* MONO_IRQ_MAP */ + cs89x_set_irq(dev); +#endif /* MONO_IRQ_MAP */ + #if ALLOW_DMA if (lp->use_dma) { if (lp->isa_config & ANY_ISA_DMA) { @@ -1502,6 +1591,9 @@ net_open(struct net_device *dev) netif_start_queue(dev); if (net_debug > 1) printk("cs89x0: net_open() succeeded\n"); +#ifdef CONFIG_PM + cs89x0_in_use = 1; +#endif return 0; bad_out: return ret; @@ -1554,6 +1646,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; + /* + * This is the estimate of how many bytes have been sent, + * we don't realy know if the packet was sent 'till we get + * the TX interrupt with a status of OK. However the interrupt + * routine does not know the length of the packet that was sent. + */ + lp->stats.tx_bytes += skb->len; dev_kfree_skb (skb); /* @@ -1625,8 +1724,13 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) if (status & TX_UNDERRUN) { if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); lp->send_underrun++; +#ifndef USE_TX_AFTER_ALL if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; +#else + /* some boards have trouble keeping up */ + lp->send_cmd = TX_AFTER_ALL; +#endif /* transmit cycle is done, although frame wasn't transmitted - this avoids having to wait for the upper @@ -1755,6 +1859,10 @@ net_close(struct net_device *dev) } #endif +#if defined(CONFIG_PM) + cs89x0_in_use = 0; +#endif + /* Update the statistics here. */ return 0; } @@ -1921,6 +2029,12 @@ int __init init_module(void) dev->irq = irq; dev->base_addr = io; +#ifdef HW_INIT_HOOK + if (cs89x_hw_init_hook(dev, -1) != 0) { + ret = -ENODEV; + goto out; + } +#endif lp = netdev_priv(dev); #if ALLOW_DMA diff --git a/drivers/net/cs89x0_defs.h b/drivers/net/cs89x0_defs.h new file mode 100644 index 00000000..af163084 --- /dev/null +++ b/drivers/net/cs89x0_defs.h @@ -0,0 +1,82 @@ + +/* linux/drivers/net/cs89x0_defs.h: cs89x0 specific settings for embedded boards + * + * Copyright (C) 2004 Georges Menie + * + */ + +#ifndef _CS89X0_DEFS_H_ +#define _CS89X0_DEFS_H_ + +#ifdef CONFIG_M68328 +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_M68EZ328 +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_M68VZ328 +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_EXCALIBUR +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_ARCH_TA7S +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_HYPERSTONE +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef CONFIG_MACH_DM270 +#include +#include +#define _CS89X0_DEFS_EMBED_ +#endif + +#ifdef _CS89X0_DEFS_EMBED_ + +/* suppress debugging output */ +#undef DEBUGGING +#define DEBUGGING 0 + +/* suppress DMA support */ +#undef ALLOW_DMA +#define ALLOW_DMA 0 + +/* suppress EEPROM support */ +#define NO_EPROM + +/* suppress request_region() call */ +#define NO_REQUEST_REGION + +/* use static IRQ mapping */ +#define MONO_IRQ_MAP + +/* don't start sending packet before the whole data + * has been written to the cs89x0 registers + */ +#define USE_TX_AFTER_ALL + +/* place a hook into the cs89x0_probe1 function + * to call cs89x_hw_init_hook() for hardware initialisation + */ +#define HW_INIT_HOOK + +#endif /* _CS89X0_DEFS_EMBED_ */ +#endif /* _CS89X0_DEFS_H_ */ diff --git a/drivers/net/cs89x0_fct.h b/drivers/net/cs89x0_fct.h new file mode 100644 index 00000000..bc6702f0 --- /dev/null +++ b/drivers/net/cs89x0_fct.h @@ -0,0 +1,34 @@ + +/* linux/drivers/net/cs89x0_fct.h: arch/platform specific code for CS89x0 + * + * Copyright (C) 2004 Georges Menie + * + */ + +#ifdef CONFIG_M68328 +#include +#endif + +#ifdef CONFIG_M68EZ328 +#include +#endif + +#ifdef CONFIG_M68VZ328 +#include +#endif + +#ifdef CONFIG_EXCALIBUR +#include +#endif + +#ifdef CONFIG_ARCH_TA7S +#include +#endif + +#ifdef CONFIG_HYPERSTONE +#include +#endif + +#ifdef CONFIG_MACH_DM270 +#include +#endif diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 6764281b..d15441a7 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1427,6 +1427,29 @@ static void __inline__ fec_request_intrs(struct net_device *dev) *gpio_pehlpar = 0xc0; } #endif + +#if defined(CONFIG_M527x) + /* Set up gpio outputs for MII lines */ + { + volatile u8 *gpio_par_fec; + volatile u16 *gpio_par_feci2c; + + gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082); + /* Set up gpio outputs for FEC0 MII lines */ + gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078); + + *gpio_par_feci2c |= 0x0f00; + *gpio_par_fec |= 0xc0; + +#if defined(CONFIG_FEC2) + /* Set up gpio outputs for FEC1 MII lines */ + gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079); + + *gpio_par_feci2c |= 0x00a0; + *gpio_par_fec |= 0xc0; +#endif /* CONFIG_FEC2 */ + } +#endif /* CONFIG_M527x */ } static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) diff --git a/drivers/net/ks8695/Makefile b/drivers/net/ks8695/Makefile new file mode 100644 index 00000000..82d98f5c --- /dev/null +++ b/drivers/net/ks8695/Makefile @@ -0,0 +1,13 @@ + +CFLAGS_KS8695 += -DRX_TASK -DTX_TASK -DARM_LINUX -DEXPORT_SYMTAB +#CFLAGS_KS8695 += -Wno-strict-prototypes + +CFLAGS_ks8695_main.o += $(CFLAGS_KS8695) +CFLAGS_ks8695_fxhw.o += $(CFLAGS_KS8695) +CFLAGS_ks8695_cache.o += $(CFLAGS_KS8695) + + +obj-$(CONFIG_ETH_KS8695) += ks8695.o + +ks8695-y := ks8695_main.o ks8695_fxhw.o ks8695_cache.o + diff --git a/drivers/net/ks8695/ks8695_cache.c b/drivers/net/ks8695/ks8695_cache.c new file mode 100644 index 00000000..0a95a326 --- /dev/null +++ b/drivers/net/ks8695/ks8695_cache.c @@ -0,0 +1,280 @@ +/* + Copyright (c) 2002, Micrel Kendin Operations + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as lruan@kendin.com + Micrel Kendin Operations + 486 Mercury Dr. + Sunnyvale, CA 94085 + + This driver is for Kendin's KS8695 SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.kendin.com or www.micrel.com + +*/ +#include "ks8695_drv.h" +#include "ks8695_cache.h" + +/* for 922T, the values are fixed */ +#if 0 +static uint32_t uICacheLineLen = 8; /* 8 dwords, 32 bytes */ +static uint32_t uICacheSize = 8192; /* 8K cache size */ +#endif + +static uint32_t bPowerSaving = FALSE; +static uint32_t bAllowPowerSaving = FALSE; + +/* + * ks8695_icache_read_c9 + * This function is use to read lockdown register + * + * Argument(s) + * NONE + * + * Return(s) + * NONE + */ +void ks8695_icache_read_c9(void) +{ + register int base; + + __asm__( + "mrc p15, 0, %0, c9, c0, 1" + : "=r" (base) + ); + + DRV_INFO("%s: lockdown index=%d", __FUNCTION__, (base >> 26)); +} + +#if 0 +/* + * ks8695_icache_lock + * This function is use to lock given icache + * + * Argument(s) + * icache_start pointer to starting icache address + * icache_end pointer to ending icache address + * + * Return(s) + * 0 if success + * error otherwise + */ +int ks8695_icache_lock(void *icache_start, void *icache_end) +{ + uint32_t victim_base = (ICACHE_VICTIM_BASE << ICACHE_VICTIM_INDEX); + int len; + spinlock_t lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; + + len = (int)(icache_end - icache_start); + DRV_INFO("%s: start=%p, end=%p, len=%d, victim=0x%x", __FUNCTION__, icache_start, icache_end, len, victim_base); + + /* if lockdown lines are more than half of max associtivity */ + if ((len / ICACHE_BYTES_PER_LINE) > (ICACHE_ASSOCITIVITY >> 1)) { + DRV_WARN("%s: lockdown lines = %d is too many, (Assoc=%d)", __FUNCTION__, (len / ICACHE_BYTES_PER_LINE), ICACHE_ASSOCITIVITY); + return -1; + } + + spin_lock_irqsave(&lock, flags); + + __asm__( + " \n\ + ADRL r0, ks8695_isr \n\ + ADRL r1, ks8695_isre \n\ + MOV r2, %1 \n\ + MCR p15, 0, r2, c9, c4, 1 \n\ +lock_loop: \n\ + MCR p15, 0, r0, c7, c13, 1 \n\ + ADD r0, r0, #32 \n\ + \n\ + AND r3, r0, #0x60 \n\ + CMP r3, #0x0 \n\ + ADDEQ r2, r2, #0x1<<26 \n\ + MCREQ p15, 0, r2, c9, c0, 1 \n\ + \n\ + CMP r0, r1 \n\ + BLE lock_loop \n\ + \n\ + CMP r3, #0x0 \n\ + ADDNE r2, r2, #0x1<<26 \n\ + MCRNE p15, 0, r2, c9, c0, 1 \n\ + " + : "=r" (len) + : "r" (victim_base) + : "r0", "r1", "r2", "r3" + ); + + ks8695_icache_read_c9(); + +#if 0 + /* following are the assemble code for icache lock down, a C version should be implemented, accordingly */ + ADRL r0, start_address ; address pointer + ADRL r1, end_address + MOV r2, #lockdown_base<<26 ; victim pointer + MCR p15, 0, r2, c9, c0, 1 + +loop + MCR p15, 0, r0, c7, c13, 1 ; prefetch ICache line + ADD r0, r0, #32 ; increment address pointer to next ICache line + + ; do we need to increment the victim pointer ? + ; thest for segment 0, and if so, increment the victim pointer + ; and write the Icache victime and lockdown base + + AND r3, r0, #0x60 ; extract the segment bits from the addr. + CMP r3, #0x0 ; test the segment + ADDEQ r2, r2, #0x1<<26 ; if segment 0, increment victim pointer + MCREQ p15, 0, r2, c9, c0, 1 ; and write ICaceh victim and lockdown + + ; have we linefilled enough code? + ; test for the address pointer being less than or equal to the end_address + ; pointer and if so, loop and perform another linefill + + CMP r0, r1 ; test for less than or equal to end_address + BLE loop ; if not, loop + + ; have we exited with r3 pointer to segment 0? + ; if so, the ICaceh victim and lockdown base has already been set to one higher + ; than the last entry written. + ; if not, increment the victim pointer and write the ICache victim and + ; lockdown base. + + CMP r3, #0x0 ; test for segments 1 to 3 + ADDNE r2, r2, #0x1 << 26 ; if address is segment 1 to 3 + MCRNE p15, 0, r2, c9, c0, 1 ; write ICache victim and lockdown base. + +#endif + + spin_unlock_irqrestore(&lock, flags); + + return 0; +} +#endif + +/* + * ks8695_icache_unlock + * This function is use to unlock the icache locked previously + * + * Argument(s) + * NONE. + * + * Return(s) + * NONE. + */ +void ks8695_icache_unlock(void) +{ +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + __asm__( + " \n\ + MOV r1, #0 \n\ + MCR p15, 0, r1, c9, c0, 1 /* reset victim base to 0 */ \n\ + " + ); + + DRV_INFO("%s", __FUNCTION__); +} + +/* + * ks8695_icache_change_policy + * This function is use to change cache policy for ARM chipset + * + * Argument(s) + * bRoundRobin round robin or random mode + * + * Return(s) + * NONE + */ +void ks8695_icache_change_policy(int bRoundRobin) +{ + uint32_t tmp; + + __asm__ ( + " \n\ + mrc p15, 0, r1, c1, c0, 0 \n\ + mov r2, %1 \n\ + cmp r2, #0 \n\ + orrne r1, r1, #0x4000 \n\ + biceq r1, r1, #0x4000 \n\ + mov %0, r1 \n\ + /* Write this to the control register */ \n\ + mcr p15, 0, r1, c1, c0, 0 \n\ + /* Make sure the pipeline is clear of any cached entries */ \n\ + nop \n\ + nop \n\ + nop" + : "=r" (tmp) + : "r" (bRoundRobin) + : "r1", "r2" + ); + +/*#ifdef DEBUG_THIS*/ + DRV_INFO("Icache mode = %s", bRoundRobin ? "roundrobin" : "random"); +/*#endif*/ +} + +/* + * ks8695_enable_power_saving + * This function is use to enable/disable power saving + * + * Argument(s) + * bSaving + * + * Return(s) + * NONE + */ +void ks8695_enable_power_saving(int bEnablePowerSaving) +{ + bAllowPowerSaving = bEnablePowerSaving; +} + +/* + * ks8695_power_saving + * This function is use to put ARM chipset in low power mode (wait for interrupt) + * + * Argument(s) + * bSaving + * + * Return(s) + * NONE + */ +void ks8695_power_saving(int bSaving) +{ + uint32_t tmp; + + /* if not allowed by configuration option */ + if (!bAllowPowerSaving) + return; + + /* if already set */ + if (bPowerSaving == bSaving) + return; + + bPowerSaving = bSaving; + + __asm__ ( + " \n\ + mov r1, %1 \n\ + mcr p15, 0, r1, c7, c0, 4 \n\ + /* Make sure the pipeline is clear of any cached entries */ \n\ + nop \n\ + nop \n\ + nop" + : "=r" (tmp) + : "r" (bSaving) + : "r1", "r2" + ); + + DRV_INFO("%s: power saving = %s", __FUNCTION__, bSaving ? "enabled" : "disabled"); +} diff --git a/drivers/net/ks8695/ks8695_cache.h b/drivers/net/ks8695/ks8695_cache.h new file mode 100644 index 00000000..a99dfce0 --- /dev/null +++ b/drivers/net/ks8695/ks8695_cache.h @@ -0,0 +1,48 @@ +/* + Copyright (c) 2002, Micrel Kendin Operations + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as lruan@kendin.com + Micrel Kendin Operations + 486 Mercury Dr. + Sunnyvale, CA 94085 + + This driver is for Kendin's KS8695 SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.kendin.com/ks8695/ + +*/ +#ifndef __KS8695_CACHE_H +#define __KS8695_CACHE_H + +#include +#include +#include +#include + +#include "ks8695_drv.h" + +/* start ICache lockdown at ICACHE_VICTIM_BASE */ +#define ICACHE_VICTIM_BASE 0 +#define ICACHE_VICTIM_INDEX 26 /* victim index bit, specific to ARM922T */ +#define ICACHE_ASSOCITIVITY 64 /* 64-WAY, specific to ARM922T */ +#define ICACHE_BYTES_PER_LINE 128 /* 8 * 4 * 4, specific to ARM922T */ + +extern void ks8695_icache_change_policy(int bRoundRobin); +/*extern int ks8695_icache_lock(void *icache_start, void *icache_end);*/ +extern void ks8695_icache_unlock(void); +extern int ks8695_icache_is_locked(void); +extern void ks8695_icache_read_c9(void); +void ks8695_power_saving(int bSaving); +void ks8695_enable_power_saving(int bEnablePowerSaving); + +#endif /* __KS8695_CACHE_H */ diff --git a/drivers/net/ks8695/ks8695_chipdef.h b/drivers/net/ks8695/ks8695_chipdef.h new file mode 100644 index 00000000..e1ef3e90 --- /dev/null +++ b/drivers/net/ks8695/ks8695_chipdef.h @@ -0,0 +1,440 @@ +/* + * ks8695_chipdef.h + * This file defines the driver-independent constants, macro and + * structures used in the Linux driver. + * + * Copyright (c) 1998-2002 by Micrel-Kendin Operations. All rights reserved. + * + * Modification History + * + * Name Date Ver Brief + * ----------- ----------- ------- ------------------------------------------ + * RLQ 05/13/2000 1.0.0.0 Modified based on KS8695 Linux driver + * + */ +#ifndef __KS8695_CHIPDEF_H +#define __KS8695_CHIPDEF_H + +#include +#include +#include +#include +#include +#include + +/* should change to system wise platform.h instead of local copy */ +//#include +//#include "platform.h" + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +#ifndef REG_MISC_CONTROL + +#define REG_MISC_CONTROL 0xEA08 +#define REG_LAN12_POWERMAGR 0xE84C +#define REG_LAN34_POWERMAGR 0xE850 + +#endif + +/* DMA related register offset */ +#define REG_TXCTRL 0x0000 +#define REG_RXCTRL 0x0004 +#define REG_TXSTART 0x0008 +#define REG_RXSTART 0x000c +#define REG_TXBASE 0x0010 +#define REG_RXBASE 0x0014 +#define REG_STATION_LOW 0x0018 +#define REG_STATION_HIGH 0x001c + +#define REG_MAC0_LOW 0x0080 +#define REG_MAC0_HIGH 0x0084 +#define REG_MAC1_LOW 0x0088 +#define REG_MAC1_HIGH 0x008c +#define REG_MAC2_LOW 0x0090 +#define REG_MAC2_HIGH 0x0094 +#define REG_MAC3_LOW 0x0098 +#define REG_MAC3_HIGH 0x009c +#define REG_MAC4_LOW 0x00a0 +#define REG_MAC4_HIGH 0x00a4 +#define REG_MAC5_LOW 0x00a8 +#define REG_MAC5_HIGH 0x00ac +#define REG_MAC6_LOW 0x00b0 +#define REG_MAC6_HIGH 0x00b4 +#define REG_MAC7_LOW 0x00b8 +#define REG_MAC7_HIGH 0x00bc +#define REG_MAC8_LOW 0x00c0 +#define REG_MAC8_HIGH 0x00c4 +#define REG_MAC9_LOW 0x00c8 +#define REG_MAC9_HIGH 0x00cc +#define REG_MAC10_LOW 0x00d0 +#define REG_MAC10_HIGH 0x00d4 +#define REG_MAC11_LOW 0x00d8 +#define REG_MAC11_HIGH 0x00dc +#define REG_MAC12_LOW 0x00e0 +#define REG_MAC12_HIGH 0x00e4 +#define REG_MAC13_LOW 0x00e8 +#define REG_MAC13_HIGH 0x00ec +#define REG_MAC14_LOW 0x00f0 +#define REG_MAC14_HIGH 0x00f4 +#define REG_MAC15_LOW 0x00f8 +#define REG_MAC15_HIGH 0x00fc + +/* register Bit field defines for Tx Ctrl and (some are shared with RX) */ +#define DMA_SOFTRESET 0x80000000 /* DMA soft reset (shared with RX) */ +#define DMA_UDPCHECKSUM 0x00040000 /* bit 18 (shared with RX) */ +#define DMA_TCPCHECKSUM 0x00020000 /* bit 17 (shared with RX) */ +#define DMA_IPCHECKSUM 0x00010000 /* bit 16 (shared with RX) */ +#define DMA_FLOWCTRL 0x00000200 /* bit 9 (shared with RX) */ +#define DMA_LOOPBACK 0x00000100 /* bit 8 */ +#define DMA_ERRORFRAME 0x00000008 /* bit 3 */ +#define DMA_PADDING 0x00000004 /* bit 2 */ +#define DMA_CRC 0x00000002 /* bit 1 */ +#define DMA_START 0x00000001 /* bit 0 (shared with RX) */ + +#define DMA_PBLTMASK 0x3f000000 /* DMA Burst Size bit mask (shared with RX) */ +#define DMA_PBLTSHIFT 24 /* DMA Burst Size bit shift */ + +/* some bits for RX Ctrl register */ +#define DMA_BROADCAST 0x00000040 /* bit 6 */ +#define DMA_MULTICAST 0x00000020 /* bit 5 */ +#define DMA_UNICAST 0x00000010 /* bit 4 */ +#define DMA_PROMISCUOUS 0x00000004 /* bit 2 */ + +/* Addition station registers */ +#define DMA_MACENABLE 0x80000000 /* enable/disable additional MAC station address */ + +enum DMAID { + DMA_WAN = 0x6000, /* WAN DMA */ + DMA_LAN = 0x8000, /* LAN DMA */ +#ifndef CONFIG_ARCH_KS8695P + DMA_HPNA= 0xA000 /* HPNA DMA */ +#endif +}; + +/* DESC and Data buffer */ +#define DESC_ALIGNMENT 16 /* two dwords */ + +/* Receive Descriptor */ +typedef struct +{ + volatile uint32_t RxFrameControl; + volatile uint32_t RxDMAFragLen; + volatile uint32_t RxDMAFragAddr; + volatile uint32_t RxDMANextPtr; +} RXDESC, *PRXDESC; + +#define DESC_OWN_BIT 0x80000000 /* shared with Tx descriptor */ + +/* In Linux, we use all 32 bits definitions! */ +/* Bits related to RxFrameControl */ +#define RFC_FS 0x40000000 /* First Descriptor of the received frame */ +#define RFC_LS 0x20000000 /* Last Descriptor of the received frame */ +#define RFC_IPE 0x10000000 /* IP checksum generation */ +#define RFC_TCPE 0x08000000 /* TCP checksum generation */ +#define RFC_UDPE 0x04000000 /* UDP checksum generation */ +#define RFC_ES 0x02000000 /* Error Summary */ +#define RFC_MF 0x01000000 /* Multicast Frame */ + +#define RFC_RE 0x00080000 /* Report on MII/GMII error */ +#define RFC_TL 0x00040000 /* Frame Too Long */ +#define RFC_RF 0x00020000 /* Runt Frame */ +#define RFC_CRC 0x00010000 /* CRC error */ +#define RFC_FT 0x00008000 /* Frame Type */ + +#define RFC_SPN_MASK 0x00f00000 /* Switch engine destination port map, 20:23 */ +#define RFC_FL_MASK 0x000007ff /* Frame Length bit mask, 0:10 */ +#define RFC_FRAMECTRL_MASK (RFC_FS | RFC_LS | RFC_ES | RFC_MF | RFC_RE | RFC_TL | RFC_CRC | RFC_FT | RFC_FL_MASK) + +/* Bits related to RxDMAFragLen */ +#define RFC_RER 0x02000000 /* Receive End of Ring */ +#define RFC_RBS_MASK 0x000007ff /* Receive buffer Size bit mask, 0:10 */ + +/* Transmit descriptor */ +typedef struct +{ + volatile uint32_t TxOwnBit; + volatile uint32_t TxFrameControl; + volatile uint32_t TxDMAFragAddr; + volatile uint32_t TxDMANextPtr; +} TXDESC, *PTXDESC; + +/* Bits related to TxFrameControl */ +#define TFC_IC 0x80000000 /* Interrupt on completion */ +#define TFC_FS 0x40000000 /* first segment */ +#define TFC_LS 0x20000000 /* last segment */ +#define TFC_IPCKG 0x10000000 /* IP checksum generation */ +#define TFC_TCPCKG 0x08000000 /* TCP checksum generation */ +#define TFC_UDPCKG 0x04000000 /* UDP checksum generation */ +#define TFC_TER 0x02000000 /* Transmit End of Ring */ + +#define TFC_SPN_MASK 0x00f00000 /* Switch engine destination port map, 20:23 */ +#define TFC_TBS_MASK 0x000007ff /* Transmit Buffer Size Mask (0:10) */ +#define TFC_FRAMECTRL_MASK (TFC_IC | TFC_FS | TFC_LS | TFC_SPN_MASK | TFC_TBS_MASK) + +/* Interrupt related (shared among IMR, IER, ISR, IPR, and IQR) */ +#define INT_WAN_LINK 0x80000000 /* WAN link change interrupt */ +#define INT_WAN_TX 0x40000000 /* WAN Tx complete interrupt */ +#define INT_WAN_RX 0x20000000 /* WAN Rx complete interrupt */ +#define INT_WAN_TX_UNAVIAL 0x10000000 /* WAN Tx desc unavailable interrupt */ +#define INT_WAN_RX_UNAVIAL 0x08000000 /* WAN Rx desc unavailable interrupt */ +#define INT_WAN_TX_STOPPED 0x04000000 /* WAN Tx stopped interrupt */ +#define INT_WAN_RX_STOPPED 0x02000000 /* WAN Rx stopped interrupt */ + +#define INT_WAN_MASK 0x7e000000 /* not include LINK interrupt bit */ + +#define INT_AMBA_BUS_ERROR 0x01000000 /* AMBA bus error interrupt */ + +#define INT_HPNA_TX 0x00800000 /* HPNA Tx complete interrupt */ +#define INT_HPNA_RX 0x00400000 /* HPNA Rx complete interrupt */ +#define INT_HPNA_TX_UNAVIAL 0x00200000 /* HPNA Tx desc unavailable interrupt */ +#define INT_HPNA_RX_UNAVIAL 0x00100000 /* HPNA Rx desc unavailable interrupt */ +#define INT_HPNA_TX_STOPPED 0x00080000 /* HPNA Tx stopped interrupt */ +#define INT_HPNA_RX_STOPPED 0x00040000 /* HPNA Rx stopped interrupt */ + +#define INT_HPNA_MASK 0x00fc0000 + +#define INT_LAN_TX 0x00020000 /* LAN Tx complete interrupt */ +#define INT_LAN_RX 0x00010000 /* LAN Rx complete interrupt */ +#define INT_LAN_TX_UNAVIAL 0x00008000 /* LAN Tx desc unavailable interrupt */ +#define INT_LAN_RX_UNAVIAL 0x00004000 /* LAN Rx desc unavailable interrupt */ +#define INT_LAN_TX_STOPPED 0x00002000 /* LAN Tx stopped interrupt */ +#define INT_LAN_RX_STOPPED 0x00001000 /* LAN Rx stopped interrupt */ + +#define INT_LAN_MASK 0x0003f000 + +#define INT_DMA_MASK 0xfefff000 /* interrupt bit mask for DMA (WAN, HPNA and LAN) */ + +#define INT_DMA_STOP_MASK (INT_WAN_TX_STOPPED | INT_WAN_RX_STOPPED | INT_HPNA_TX_STOPPED | INT_HPNA_RX_STOPPED | INT_LAN_TX_STOPPED | INT_LAN_RX_STOPPED) +#define INT_TX_BIT BIT(5) +#define INT_RX_BIT BIT(4) +#define INT_TX_UNAVAIL_BIT BIT(3) +#define INT_RX_UNAVAIL_BIT BIT(2) +#define INT_TX_STOPPED_BIT BIT(1) +#define INT_RX_STOPPED_BIT BIT(0) + +/* MAC address */ +#define MAC_ADDRESS_LEN 6 +#define MAC_MAX_EXTRA 16 + +typedef enum { + LED_SPEED, /* 0 */ + LED_LINK, + LED_FD, /* full duplex */ + LED_COLLISION, + LED_ACTIVITY, + LED_FD_COLLISION, /* full duplex/collision */ + LED_LINK_ACTIVITY, /* link/activities */ +} LED_SELECTOR; + +/* register Bit field for Switch control 0 */ +#define SW_CTRL0_AUTO_FAST_AGING 0x00100000 /* automic fast aging when link changed detected */ +#define SW_CTRL0_ERROR_PKT 0x00080000 /* pass all error packets */ +#define SW_CTRL0_ENABLE_PORT5 0x00040000 /* enable port 5 flow control */ +#define SW_CTRL0_ENABLE_PORTS 0x00020000 /* enable flow control for port 1 - 4 */ +#define SW_CTRL0_BUFFER_SHARE 0x00010000 /* buffer share mode */ +#define SW_CTRL0_AGING_ENABLE 0x00008000 /* aging enable */ +#define SW_CTRL0_FAST_AGING 0x00004000 /* fast aging enable */ +#define SW_CTRL0_FAST_BACKOFF 0x00002000 /* fast back off */ +#define SW_CTRL0_MISMATCH_DISCARD 0x00001000 /* VLAN mismatch discard */ +#define SW_CTRL0_NO_BCAST_STORM_PROT 0x00000800 /* no broadcast storm proection tp ,cast pkts */ +#define SW_CTRL0_PREAMBLE_MODE 0x00000400 /* back pressure mode */ +#define SW_CTRL0_FLOWCTRL_FAIR 0x00000200 /* flow control fair mode */ +#define SW_CTRL0_COLLISION_DROP 0x00000100 /* no excessive collision drop */ +#define SW_CTRL0_LEN_CHECKING 0x00000080 /* enforced max length checking */ +#define SW_CTRL0_6K_BUFFER 0x00000040 /* 6K byte buffer per port reserved for high priority pkts */ +#define SW_CTRL0_BACK_PRESSURE 0x00000020 /* back pressure enable */ +#define SW_CTRL0_SWITCH_ENABLE 0x00000001 /* enable switch bit */ + +/* register Bit field for Auto Regotiation */ +#define SW_AUTONEGO_COMPLETE 0x00004000 /* auto nego completed */ +#define SW_AUTONEGO_RESTART 0x00002000 /* auto nego restart */ +#define SW_AUTONEGO_ADV_PUASE 0x00001000 /* auto nego advertise PAUSE */ +#define SW_AUTONEGO_ADV_100FD 0x00000800 /* auto nego advertise 100 FD */ +#define SW_AUTONEGO_ADV_100HD 0x00000400 /* auto nego advertise 100 HD */ +#define SW_AUTONEGO_ADV_10FD 0x00000200 /* auto nego advertise 10 FD */ +#define SW_AUTONEGO_ADV_10HD 0x00000100 /* auto nego advertise 10 HD */ +#define SW_AUTONEGO_STAT_LINK 0x00000080 /* auto nego link status */ +#define SW_AUTONEGO_STAT_DUPLEX 0x00000040 /* auto nego duplex status (solved) */ +#define SW_AUTONEGO_STAT_SPEED 0x00000020 /* auto nego speed status (solved) */ +#define SW_AUTONEGO_PART_PAUSE 0x00000010 /* auto nego parterner pause */ +#define SW_AUTONEGO_PART_100FD 0x00000008 /* auto nego parterner 100 FD */ +#define SW_AUTONEGO_PART_100HD 0x00000004 /* auto nego parterner 100 HD */ +#define SW_AUTONEGO_PART_10FD 0x00000002 /* auto nego parterner 10 FD */ +#define SW_AUTONEGO_PART_10HD 0x00000001 /* auto nego parterner 10 HD */ + +#define SW_AUTONEGO_ADV_MASK 0x00001f00 + +#define SW_MAX_LAN_PORTS 4 /* max LAN ports */ + +/* bits for SNMP data register (SEMCD) */ +#ifndef CONFIG_ARCH_KS8695P +#define SW_SNMP_DATA_VALID 0x80000000 /* counter value is valid */ +#define SW_SNMP_DATA_OVERFLOW 0x40000000 /* counter is overflow */ +#else +#define SW_SNMP_DATA_OVERFLOW 0x80000000 /* counter is overflow */ +#define SW_SNMP_DATA_VALID 0x40000000 /* counter value is valid */ +#endif + +enum PORTS { + SW_PORT_1 = 0, + SW_PORT_2, + SW_PORT_3, + SW_PORT_4 +}; + +/* bits related to power management */ +#define POWER_POWERDOWN 0x00000010 /* port power down */ +#define POWER_DMDX_DISABLE 0x00000008 /* disable auto MDI/MDIX */ +#define POWER_FORCE_MDIX 0x00000004 /* if auto MDI/MDIX is disabled, force PHY into MDIX mode */ +#define POWER_LOOPBACK 0x00000002 /* PHY loopback */ + +#define SW_PHY_AUTO 0 /* autosense */ +#define SW_PHY_10BASE_T 1 /* 10Base-T */ +#define SW_PHY_10BASE_T_FD 2 /* 10Base-T Full Duplex */ +#define SW_PHY_100BASE_TX 3 /* 100Base-TX */ +#define SW_PHY_100BASE_TX_FD 4 /* 100Base-TX Full Duplex */ + +#define SW_PHY_DEFAULT SW_PHY_AUTO + +enum SPANNINGTREE { + SW_SPANNINGTREE_NONE, /* no spanning tree */ + SW_SPANNINGTREE_RX, /* spanning tree, RX only */ + SW_SPANNINGTREE_TX, /* spanning tree, TX only */ + SW_SPANNINGTREE_ALL, /* spanning tree, both TX/RX */ +}; + +/* bits related to port configuration register */ +#define SW_PORT_DISABLE_AUTONEG 0x00008000 /* port disable auto nego */ +#define SW_PORT_100BASE 0x00004000 /* force 100 when auto nego disabled */ +#define SW_PORT_FULLDUPLEX 0x00002000 /* force full duplex when auto nego disabled */ +#define SW_PORT_TX_SPANNINGTREE 0x00000080 /* spanning tree transmit enable */ +#define SW_PORT_RX_SPANNINGTREE 0x00000040 /* spanning tree receive enable */ +#define SW_PORT_NO_SPANNINGTREE 0x00000020 /* spanning tree disable */ +#define SW_PORT_STORM_PROCTION 0x00000010 /* broadcast storm protection (ingress) */ +#define SW_PORT_HI_PRIORITY 0x00000008 /* high priority (ingress) */ +#define SW_PORT_TOS_ENABLE 0x00000004 /* Enable TOS based priotiry classification (ingress) */ +#define SW_PORT_8021Q_ENABLE 0x00000002 /* Enable 802.1Q based priotiry classification (ingress) */ +#define SW_PORT_PRIOTIRY_ENABLE 0x00000001 /* Enable priotiry function on the port (egress) */ + +/* port 5 only */ +#define SW_PORT_RX_DIRECT_MODE 0x00004000 /* receive direct mode for port 5 */ +#define SW_PORT_TX_PRETAG_MODE 0x00002000 /* transmit pre-tag mode for port 5 */ + +typedef struct _PORT_INFO { + uint16_t usTag; /* tag value for the port (ingress) */ + uint8_t byCrossTalkMask; /* specify ports that this port can talk to */ + uint8_t byStormProtection; /* broadcast storm protection */ + uint8_t bySpanningTree; /* spanning tree */ + uint8_t byDisableSpanningTreeLearn; /* disable spanning tree learn for the port */ + uint8_t byIngressPriority; /* ingress priority */ + uint8_t byIngressPriorityTOS; /* TOS based ingress priority */ + uint8_t byIngressPriority802_1P;/* 802.1p based ingress priority */ + uint8_t byEgressPriority; /* egress priority */ +} PORT_INFO, *PPORT_INFO; + +typedef struct _DMA_INFO { + unsigned short usDMAId; /* DMAID */ + int32_t nBaseAddr; /* base address */ + int32_t nOffset; /* DMA register offset */ + uint8_t bUseFIQ; /* use FIQ or not */ + uint32_t *pbaseVa; + uint32_t nResetCount; /* DMA reset counter */ + + /* interrupt related */ + uint32_t uIntMask; /* interrupt mask checked within ISR */ + uint32_t uLinkIntMask; /* WAN link interrupt mask checked within ISR */ + uint32_t uIntShift; /* interrupt bit shift */ + + /* mac */ + uint8_t stMacStation[MAC_ADDRESS_LEN]; + uint8_t stMacCurrent[MAC_ADDRESS_LEN]; + uint8_t stSwitchMac[MAC_ADDRESS_LEN]; + + /* spinlock */ + spinlock_t lock; /* spin lock */ + spinlock_t lock_refill; /* spin lock */ + + /* Tx related */ + uint8_t bTxStarted; /* Tx DMA started or stopped! */ + uint8_t bTxFlowCtrl; /* flow control for Tx DMA */ + uint8_t bTxOffLoad; /* enable/disable Task offload for Tx DMA */ + uint8_t byTxPBL; /* Tx PBL */ + uint8_t bTxChecksum; /* checksum enable/disable indicator */ + uint8_t bTxNoResource; /* flag indicates out of Tx resource */ + uint32_t uDebugDumpTxPkt; /* flag to dump tx packet for debugging */ + + /* Tx desc related */ + int32_t nTxDesc; /* number of Tx descriptors */ + int32_t nTxDescNextAvail; /* next available Tx descriptor */ + int32_t nTxDescUsed; /* used Tx descriptor */ + volatile int32_t nTransmitCount; /* number of packets to transmit */ + int32_t nTxProcessedCount; /* number of packets to transmitted */ + int32_t nTxDescTotal; /* total number fo Tx descriptors */ + int32_t nTransmitCoalescing; /* Tx packets coalescing count */ + + TXDESC *pTxDescriptors; + dma_addr_t TxDescDMA; + struct ks8695_buffer *pTxSkb; + atomic_t nTxDescAvail; + + /* Rx related */ + uint8_t bRxStarted; /* Rx DMA started or stopped! */ + uint8_t bRxFlowCtrl; /* flow control for Rx DMA */ + uint8_t bPort5FlowCtrl; /* flow control for LAN port 5 */ + uint8_t bPortsFlowCtrl; /* flow control for LAN port 1 - 4 */ + uint8_t byRxPBL; /* Rx PBL */ + uint8_t bRxChecksum; /* checksum enable/disable indicator */ + uint32_t uRxBufferLen; /* rx buffer length */ + uint32_t uDebugDumpRxPkt; /* flag to dump rx packet for debugging */ + uint32_t uRx1518plus; /* rx packet counter for 1518 plus for debugging */ + uint32_t uRxUnderSize; /* rx packet counter for under size packets (< 64) */ + uint32_t nMaxFilledCount; /* max refilled count */ + uint32_t nMaxProcessedCount; /* max rx pkt count in one process cycle */ + + int32_t nRxDesc; /* number of Rx descriptors */ + int32_t nRxDescNextAvail; /* next available Rx descriptor */ + int32_t nRxDescNextToFill; /* next Rx desc to fill new buffer to */ + RXDESC *pRxDescriptors; + dma_addr_t RxDescDMA; + struct ks8695_buffer *pRxSkb; + atomic_t RxDescEmpty; /* atomic flag for empty Rx descriptor */ + struct tasklet_struct rx_fill_tasklet; + int32_t nRxDescTotal; /* total number fo Rx descriptors */ + int32_t rx_fill_scheduled; /* flag for rx fill schedule routine */ + +#ifdef RX_TASK + struct tasklet_struct rx_tasklet; + int32_t rx_scheduled; /* flag for rx receive task schedule routine */ +#endif + +#ifdef TX_TASK + struct tasklet_struct tx_tasklet; + int32_t tx_scheduled; /* flag for tx receive task schedule routine */ +#endif + + /* PHY related */ + uint8_t bAutoNegoInProgress[SW_MAX_LAN_PORTS];/* if set, means that auto nego is in progress!!! */ + uint8_t bLinkActive[SW_MAX_LAN_PORTS]; /* flag indicates whether link is active or not */ + uint8_t bLinkChanged[SW_MAX_LAN_PORTS]; /* link changed indicator */ + uint8_t bHalfDuplex[SW_MAX_LAN_PORTS]; /* HD/FD */ + uint16_t usCType[SW_MAX_LAN_PORTS]; /* Convert type */ + uint16_t usLinkSpeed[SW_MAX_LAN_PORTS]; /* link speed */ + PORT_INFO port[SW_MAX_LAN_PORTS + 1]; /* port related */ + int32_t nLinkChangeCount; /* trace link change count */ + uint8_t byDisableAutoNego[SW_MAX_LAN_PORTS]; /* auto nego/disable auto nego/partial auto nego */ + uint8_t bHalfDuplexDetected[SW_MAX_LAN_PORTS]; /* HD/FD detected based on partner's settings */ + + uint8_t bRxDirectMode; /* for port 5 only */ + uint8_t bTxRreTagMode; /* for port 5 only */ + + uint8_t bPowerDownReset; /* perform powerdown reset instead of soft reset */ +} DMA_INFO, *PDMA_INFO; + +typedef struct _INTCFG { + uint8_t bFIQ; /* use FIQ */ + uint8_t byPriority; /* priority level for IRQ */ +} INTCFG, *PINTCFG; + +#endif /*__KS8695_CHIPDEF_H*/ diff --git a/drivers/net/ks8695/ks8695_drv.h b/drivers/net/ks8695/ks8695_drv.h new file mode 100644 index 00000000..535669de --- /dev/null +++ b/drivers/net/ks8695/ks8695_drv.h @@ -0,0 +1,204 @@ +/* + Copyright (c) 2002, Micrel Kendin Operations + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as lruan@kendin.com + Micrel Kendin Operations + 486 Mercury Dr. + Sunnyvale, CA 94085 + + This driver is for Kendin's KS8695 SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.kendin.com/ks8695/ + +*/ +#ifndef __KS8695DRV_H +#define __KS8695DRV_H + +struct _ADAPTER_STRUCT; +typedef struct _ADAPTER_STRUCT ADAPTER_STRUCT, *PADAPTER_STRUCT; + +#include "ks8695_kcompat.h" +//#include +#include +#include +#include "ks8695_chipdef.h" + +#include "ks8695_fxhw.h" + +#define BAR_0 0 + +#define DRV_INFO(S, args...) printk(KERN_INFO "eth info: " S "\n" , ##args) +#define DRV_DBG(S, args...) printk(KERN_DEBUG "eth dbg: " S "\n" , ## args) +#define DRV_ERR(S, args...) printk(KERN_ERR "eth err: " S "\n" , ## args) +#define DRV_WARN(S, args...) printk(KERN_WARNING "eth warning: " S "\n" , ## args) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/* command line options defaults */ +#define TXDESC_DEFAULT 128 +#define TXDESC_MAX 256 +#define TXDESC_MIN 64 + +#define RXDESC_DEFAULT 128 +#define RXDESC_MAX 256 +#define RXDESC_MIN 64 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#if defined(CONFIG_MACH_LITE300) || defined(CONFIG_MACH_CM4002) || \ + defined(CONFIG_MACH_CM4008) || defined(CONFIG_MACH_CM41xx) || \ + defined(CONFIG_MACH_SE4200) +#define RXCHECKSUM_DEFAULT OPTION_DISABLED +#define TXCHECKSUM_DEFAULT OPTION_DISABLED +#else +#define RXCHECKSUM_DEFAULT OPTION_ENABLED +#define TXCHECKSUM_DEFAULT OPTION_ENABLED +#endif +#define FLOWCONTROL_DEFAULT OPTION_ENABLED + +#define PBL_DEFAULT 8 /* 0 for unlimited, other value for (4 * x), our VxWorks shows that 8 is optimized */ + +// Supported RX Buffer Sizes +#define BUFFER_1568 1568 /* 0x620 */ +#define BUFFER_2048 2048 +#define BUFFER_4K 4096 + +// standard ethernet header +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 +#define MINIMUM_ETHERNET_PACKET_SIZE 60 +#define ETH_CRC_LENGTH 4 +#define ETH_LENGTH_OF_ADDRESS 6 + +#define KS8695_ROUNDUP(size, unit) (unit * ((size + unit - 1) / unit)) + +// socket buffer +struct ks8695_buffer { + struct sk_buff *skb; + dma_addr_t dma; + unsigned long length; + int direction; +}; + +// Adapter->flags definitions +#define KS8695_BOARD_OPEN 0 + +/* board specific private data structure */ +struct _ADAPTER_STRUCT { + struct _ADAPTER_STRUCT *next; + struct _ADAPTER_STRUCT *prev; + + unsigned long flags; + uint32_t bd_number; + struct timer_list timer_id; + + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + DMA_INFO stDMAInfo; /* DMA information */ + u8 rev; /* revision, for KS8695P */ +}; + +#define DI (Adapter->stDMAInfo) /* Dma Information */ +#define DPI (Adapter->stDMAInfo.port) /* Dma Port Inforamtion */ + +/* ks8695_main.c */ +extern int ks8695_init_module(void); +extern void ks8695_exit_module(void); +extern int ks8695_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +extern void ks8695_remove(struct pci_dev *pdev); +extern void ks8695_delete(PADAPTER_STRUCT Adapter); +extern int ks8695_open(struct net_device *netdev); +extern int ks8695_close(struct net_device *netdev); +extern void ks8695_set_multi(struct net_device *netdev); +extern int ks8695_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +extern struct net_device_stats *ks8695_get_stats(struct net_device *netdev); +extern int ks8695_change_mtu(struct net_device *netdev, int new_mtu); +extern int ks8695_set_mac(struct net_device *netdev, void *p); +extern irqreturn_t ks8695_isr(int irq, void *data); +/* for I-cache lockdown or FIQ purpose */ +extern void ks8695_isre(void); /* to fix compiler complain if integrated with kernel */ +extern irqreturn_t ks8695_isr_link(int irq, void *data); +extern int ks8695_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +extern void ks8695_watchdog(unsigned long data); + +/* ks8695_fxhw.c */ +extern BOOLEAN ks8695_ChipInit(PADAPTER_STRUCT Adapter, BOOLEAN bResetPhy); +extern void macSetLoopback(PADAPTER_STRUCT Adapter, BOOLEAN bLoopback); +extern void macStopAll(PADAPTER_STRUCT Adapter); +extern void macStartRx(PADAPTER_STRUCT Adapter, BOOLEAN bStart); +extern void macStartTx(PADAPTER_STRUCT Adapter, BOOLEAN bStart); +extern int macSetStationEx(PADAPTER_STRUCT Adapter, UCHAR *pMac, UINT uIndex); +extern int macResetStationEx(PADAPTER_STRUCT Adapter, UCHAR *pMac); +extern void macGetStationAddress(PADAPTER_STRUCT Adapter, uint8_t *pMacAddress); +extern void macEnableInterrupt(PADAPTER_STRUCT Adapter, BOOLEAN bEnable); +extern void macSetStationAddress(PADAPTER_STRUCT Adapter, uint8_t *pMacAddress); +extern int macGetIndexStationEx(PADAPTER_STRUCT Adapter); + +/* switch related */ +extern void swSetLED(PADAPTER_STRUCT Adapter, BOOLEAN bLED1, LED_SELECTOR nSel); +extern int swGetPhyStatus(PADAPTER_STRUCT Adapter, UINT uPort); +extern UINT swReadSNMPReg(PADAPTER_STRUCT Adapter, UINT uIndex); +extern void swResetSNMPInfo(PADAPTER_STRUCT Adapter); +extern void swEnableSwitch(PADAPTER_STRUCT Adapter, UINT enable); +extern void swDetectPhyConnection(PADAPTER_STRUCT Adapter, UINT uPort); +extern BOOLEAN swPhyLoopback(PADAPTER_STRUCT Adapter, UINT uPort, BOOLEAN bLoopback); +extern BOOLEAN swGetWANLinkStatus(PADAPTER_STRUCT Adapter); +extern void swAutoNegoAdvertisement(PADAPTER_STRUCT Adapter, UINT uPort); +extern void swPhyReset(PADAPTER_STRUCT Adapter, UINT uPort); +extern void swConfigureMediaType(PADAPTER_STRUCT Adapter, UINT uPort, UINT uSpeed, UINT uDuplex); +extern void swConfigTagRemoval(PADAPTER_STRUCT Adapter, UINT uPort, UINT bRemoval); +extern void swConfigTagInsertion(PADAPTER_STRUCT Adapter, UINT uPort, UINT bInsert); +extern void swConfigurePort(PADAPTER_STRUCT Adapter, UINT uPort); + +extern void gpioSet(PADAPTER_STRUCT Adapter, UINT uPort, UINT bSet); + +#ifdef CONFIG_ARCH_KS8695P +extern void enablePhyLoopback(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable); +extern void enableRemoteLoopback(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable); +extern void enablePhyIsolate(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable); +extern void forcePhyLink(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable); +extern void dumpDynamicMacTable(PADAPTER_STRUCT Adapter); +extern void dumpStaticMacTable(PADAPTER_STRUCT Adapter); +void enableTxRateControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable, + UINT bEnableLow, UINT bEnableHigh); +void enableRxRateControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable, + UINT bEnableLow, UINT bEnableHigh); +void setTxRate(PADAPTER_STRUCT Adapter, UINT uPort, UINT lrate, UINT hrate); +void setRxRate(PADAPTER_STRUCT Adapter, UINT uPort, UINT lrate, UINT hrate); +#endif + +#endif /* __KS8695DRV_H */ diff --git a/drivers/net/ks8695/ks8695_fxhw.c b/drivers/net/ks8695/ks8695_fxhw.c new file mode 100644 index 00000000..8062c683 --- /dev/null +++ b/drivers/net/ks8695/ks8695_fxhw.c @@ -0,0 +1,2753 @@ +/* + Copyright (c) 2002-2003, Micrel Semiconductor + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as liqun.ruan@micrel.com + Micrel Semiconductor + 1931 Fortune Dr. + San Jose, CA 95131 + + This driver is for Micrel's KS8695/KS8695P SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.micrel.com/ks8695/ not ready yet!!! + +*/ +#include "ks8695_drv.h" +#include "ks8695_chipdef.h" +#include "ks8695_ioctrl.h" +#include "ks8695_cache.h" + +static int macReset(PADAPTER_STRUCT Adapter); +static void macConfigure(PADAPTER_STRUCT Adapter); +static void macConfigureFlow(PADAPTER_STRUCT Adapter, uint8_t bFlowCtrl); +static void macConfigureInterrupt(PADAPTER_STRUCT Adapter); + +static void swConfigure(PADAPTER_STRUCT Adapter); +static void swCreateLookUpTable(PADAPTER_STRUCT Adapter); + +static void gpioConfigure(PADAPTER_STRUCT Adapter); + +#ifdef CONFIG_ARCH_KS8695P +void forceFlowControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bOn); +void backPressureEnable(PADAPTER_STRUCT Adapter, UINT uPort, UINT bOn); +#endif + +/* + * ks8695_ChipInit + * This function is used to do chip initialization. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * bResetPhy flag indicates whether to reset PHY as well + * + * Return(s) + * TRUE if success + * FALSE otherwise + */ +BOOLEAN ks8695_ChipInit(PADAPTER_STRUCT Adapter, BOOLEAN bResetPhy) +{ + BOOLEAN bStatus; + struct net_device *netdev = Adapter->netdev; + UINT i; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + if (bResetPhy) { + /* phy related initialization */ + i = 0; + swPhyReset(Adapter, i); + if (DMA_LAN == DI.usDMAId) { + for (i = 1; i < SW_MAX_LAN_PORTS; i++) { + swPhyReset(Adapter, i); + /* turn off GPIO, to make sure that if there is no cable connection, no light */ + gpioSet(Adapter, i, FALSE); + } + } + swAutoNegoAdvertisement(Adapter, 0); + if (DMA_LAN == DI.usDMAId) { + for (i = 1; i < SW_MAX_LAN_PORTS; i++) { + swAutoNegoAdvertisement(Adapter, i); + } + } + } + + /* setup mac related stuff */ + bStatus = macReset(Adapter); + if (bStatus) { + DRV_ERR("%s: macReset failed", __FUNCTION__); + return FALSE; + } + macConfigure(Adapter); + macConfigureInterrupt(Adapter); + + /* turn off GPIO, to make sure that if there is no cable connection, no light */ + gpioSet(Adapter, 0, FALSE); + /* configuration switch related to LAN only */ + if (DMA_LAN == DI.usDMAId) { + swConfigure(Adapter); + swCreateLookUpTable(Adapter); + for (i = 1; i < SW_MAX_LAN_PORTS; i++) { + /* turn off GPIO, to make sure that if there is no cable connection, no light */ + gpioSet(Adapter, i, FALSE); + } + } + + /* copy the MAC address out of Station registers */ + macSetStationAddress(Adapter, DI.stMacStation); + if (netdev->addr_len < MAC_ADDRESS_LEN) + netdev->addr_len = MAC_ADDRESS_LEN; + memcpy(netdev->dev_addr, DI.stMacStation, netdev->addr_len); + memcpy(DI.stMacCurrent, netdev->dev_addr, netdev->addr_len); + +#ifdef DEBUG_THIS + DRV_INFO("MAC address %02X:%02X:%02X:%02X:%02X:%02X", + DI.stMacStation[0], + DI.stMacStation[1], + DI.stMacStation[2], + DI.stMacStation[3], + DI.stMacStation[4], + DI.stMacStation[5]); +#endif + + gpioConfigure(Adapter); + + /*RLQ, 11/20/2002, fix based on AN112. Changing transmitter gain in KS8695 to improve + the calbe length at which the Ethernet can operate */ + if (0 == Adapter->rev) { + /* for KS8695 */ + KS8695_WRITE_REG(KS8695_WAN_PHY_CONTROL, 0x0000b000); + } + else { + /* for KS8695P, rev A */ + KS8695_WRITE_REG(KS8695_WAN_PHY_CONTROL, 0x0200b000); + } + + return bStatus ? FALSE : TRUE; +} + +#define IRQ_WAN_LEVEL 12 +#define IRQ_LAN_LEVEL 10 +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) +#define IRQ_HPNA_LEVEL 8 +#endif + +/* move to source file later */ +static INTCFG stDMAIntCfg[32] = { + { 0, -1 }, /* -1 don't touch, it's not ours */ + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, /* bit 11 */ + + { 0, 0x0b }, /* bit 12, LAN */ + { 0, 0x0b }, + { 0, 0x0a }, + { 0, 0x0a }, + { 0, 0x0f }, + { 0, 0x0f }, + +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + { 0, IRQ_HPNA_LEVEL }, /* bit 18, HPNA */ + { 0, IRQ_HPNA_LEVEL }, + { 0, IRQ_HPNA_LEVEL }, + { 0, IRQ_HPNA_LEVEL }, + { 0, IRQ_HPNA_LEVEL }, + { 0, IRQ_HPNA_LEVEL }, +#else + { 0, -1 }, /* bit 18, KS8695P doesn't have HPNA port */ + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, + { 0, -1 }, +#endif + { 0, -1 }, /* bit 24 */ + + { 0, 0x0b }, /* bit 25, WAN */ + { 0, 0x0b }, + { 0, 0x0a }, + { 0, 0x0a }, + { 0, 0x0f }, + { 0, 0x0f }, + { 0, IRQ_WAN_LEVEL } /* WAN link */ +}; + +/* + * macReset + * This function will execute a soft reset the chipset. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * 0 if success + * none zero otherwise + */ +int macReset(PADAPTER_STRUCT Adapter) +{ + int nTimeOut = 1000; + UINT32 uReg; + unsigned long flags; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + spin_lock_irqsave(&DI.lock, flags); + /*spin_lock(&DI.lock);*/ + /* disable IER if any */ + uReg = KS8695_READ_REG(KS8695_INT_ENABLE); + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + uReg &= ~INT_HPNA_MASK; + break; +#endif + + case DMA_LAN: + uReg &= ~INT_LAN_MASK; + break; + + default: + case DMA_WAN: + uReg &= ~INT_WAN_MASK; + break; + } + KS8695_WRITE_REG(KS8695_INT_ENABLE, uReg); + /*spin_unlock(&DI.lock);*/ + spin_unlock_irqrestore(&DI.lock, flags); + + /* reset corresponding register and wait for completion */ + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, DMA_SOFTRESET); + do + { + DelayInMilliseconds(1); + uReg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + if (!(uReg & DMA_SOFTRESET)) + break; + } while (--nTimeOut); + + if (nTimeOut < 1) { + DRV_ERR("%s> timeout error", __FUNCTION__); + return -ETIMEDOUT; + } + + /* clear statistic counters */ + swResetSNMPInfo(Adapter); +#ifdef DEBUG_THIS + DRV_INFO("%s> succeeded (timeout count=%d)", __FUNCTION__, nTimeOut); +#endif + + return 0; +} + +/* + * macConfigure + * This function is used to set MAC control register based on configurable + * option settings. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE + */ +void macConfigure(PADAPTER_STRUCT Adapter) +{ + UINT uRxReg, uTxReg; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* read TX mode register */ + uTxReg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + /* clear PBL bits first */ + uTxReg &= ~DMA_PBLTMASK; /* 29:24 */ + if (DI.byTxPBL) + uTxReg |= ((uint32_t)DI.byTxPBL << DMA_PBLTSHIFT); + + if (DI.bTxChecksum) { + uTxReg |= (DMA_IPCHECKSUM | DMA_TCPCHECKSUM | DMA_UDPCHECKSUM); + } + else { + uTxReg &= ~(DMA_IPCHECKSUM | DMA_TCPCHECKSUM | DMA_UDPCHECKSUM); + } + + if (DI.bTxFlowCtrl) + { + uTxReg |= DMA_FLOWCTRL; + } + else { + uTxReg &= ~DMA_FLOWCTRL; + } + uTxReg |= (DMA_PADDING | DMA_CRC); + /* write TX mode register */ + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, uTxReg); + + /* read RX mode register */ + uRxReg = KS8695_READ_REG(REG_RXCTRL + DI.nOffset); + /* clear PBL bits first */ + uRxReg &= ~DMA_PBLTMASK; /* 29:24 */ + if (DI.byRxPBL) + uRxReg |= ((uint32_t)DI.byRxPBL << DMA_PBLTSHIFT); + /* checksum */ + if (DI.bRxChecksum) { + uRxReg |= (DMA_IPCHECKSUM | DMA_TCPCHECKSUM | DMA_UDPCHECKSUM); + } + else { + uRxReg &= ~(DMA_IPCHECKSUM | DMA_TCPCHECKSUM | DMA_UDPCHECKSUM); + } + /* flow control */ + if (DI.bRxFlowCtrl) + { + uRxReg |= DMA_FLOWCTRL; + } + else { + uRxReg &= ~DMA_FLOWCTRL; + } + /* set unicast only, and let ks8695_set_multi function to set the rest */ + uRxReg |= DMA_UNICAST; + + /* write RX mode register */ + KS8695_WRITE_REG(REG_RXCTRL + DI.nOffset, uRxReg); +} + +/* + * macConfigureFlow + * This function is used to set mac flow control as a workaround for WAN port. + * option settings. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * bFlowCtrl flow control to set + * + * Return(s) + * NONE + */ +void macConfigureFlow(PADAPTER_STRUCT Adapter, uint8_t bFlowCtrl) +{ + UINT uRxReg, uTxReg; + BOOLEAN bTxStarted, bRxStarted; + +#ifdef DEBUG_THIS + DRV_INFO("%s: flowctrl = %d", __FUNCTION__, bFlowCtrl); +#endif + + /* need to stop mac engines if started */ + bTxStarted = DI.bTxStarted; + bRxStarted = DI.bRxStarted; + if (bRxStarted) + macStartRx(Adapter, FALSE); + if (bTxStarted) + macStartTx(Adapter, FALSE); + + /* read TX mode register */ + uTxReg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + if (bFlowCtrl) + { + uTxReg |= DMA_FLOWCTRL; + } + else { + uTxReg &= ~DMA_FLOWCTRL; + } + /* write TX mode register */ + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, uTxReg); + + /* read RX mode register */ + uRxReg = KS8695_READ_REG(REG_RXCTRL + DI.nOffset); + if (bFlowCtrl) + { + uRxReg |= DMA_FLOWCTRL; + } + else { + uRxReg &= ~DMA_FLOWCTRL; + } + /* write RX mode register */ + KS8695_WRITE_REG(REG_RXCTRL + DI.nOffset, uRxReg); + + if (bRxStarted) + macStartRx(Adapter, TRUE); + if (bTxStarted) + macStartTx(Adapter, TRUE); +} + +/* + * macSetLoopback + * This function is used to set MAC lookback mode (for debugging purpose) + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE + */ +void macSetLoopback(PADAPTER_STRUCT Adapter, BOOLEAN bLoopback) +{ + UINT uTxReg; + BOOLEAN bTxStarted, bRxStarted; + + bTxStarted = DI.bTxStarted; + bRxStarted = DI.bRxStarted; + if (bRxStarted) + macStartRx(Adapter, FALSE); + if (bTxStarted) + macStartTx(Adapter, FALSE); + + /* read TX mode register */ + uTxReg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + + if (bLoopback) + { + uTxReg |= DMA_LOOPBACK; + } + else { + uTxReg &= ~DMA_LOOPBACK; + } + + /* write TX mode register */ + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, uTxReg); + + if (bRxStarted) + macStartRx(Adapter, TRUE); + if (bTxStarted) + macStartTx(Adapter, TRUE); +} + +/* + * macStartRx + * This routine will start/stop RX machine. + * + * Inputs: + * Adapter pointer to ADAPTER_STRUCT data structure. + * bStart TRUE if start Rx machine, FALSE if stop it + * + * Returns: + * NONE + */ +void macStartRx(PADAPTER_STRUCT Adapter, BOOLEAN bStart) +{ + UINT32 uReg; + + uReg = KS8695_READ_REG(REG_RXCTRL + DI.nOffset); + if (bStart) { + /* start RX machine */ + uReg |= DMA_START; + DI.bRxStarted = FALSE; + } else { + /* Stop RX machine */ + uReg &= ~DMA_START; + DI.bRxStarted = FALSE; + } + KS8695_WRITE_REG(REG_RXCTRL + DI.nOffset, uReg); + + /* if there descriptors available for rx, tick off Rx engine */ + if (bStart) { + if (atomic_read(&DI.RxDescEmpty) < DI.nRxDescTotal) { + KS8695_WRITE_REG(REG_RXSTART + DI.nOffset, 1); + } + } + else { + /* clear corresponding ISR bits after stopped */ + KS8695_WRITE_REG(KS8695_INT_STATUS, DI.uIntMask); + } +} + +/* + * macStartTx + * This routine will start/stop TX machine. + * + * Inputs: + * Adapter pionter to ADAPTER_STRUCT data structure. + * bStart TRUE if start Tx machine, FALSE if stop it + * + * Returns: + * NONE + */ +void macStartTx(PADAPTER_STRUCT Adapter, BOOLEAN bStart) +{ + UINT32 uReg; + + uReg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + if (bStart) { + /* start TX machine */ + uReg |= DMA_START; + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, uReg); + DI.bTxStarted = FALSE; + /* clear corresponding ISR bits after stopped */ + KS8695_WRITE_REG(KS8695_INT_STATUS, DI.uIntMask); + } else { + /* Stop TX machine */ + uReg &= ~DMA_START; + KS8695_WRITE_REG(REG_TXCTRL + DI.nOffset, uReg); + DelayInMilliseconds(2); + DI.bTxStarted = FALSE; + } +} + +/* + * macStopAll + * This function is use to stop both Tx/Rx. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void macStopAll(PADAPTER_STRUCT Adapter) +{ + /* stop Rx and Tx */ + macStartRx(Adapter, FALSE); + macStartTx(Adapter, FALSE); + + /* disable interrupt!!! */ + macEnableInterrupt(Adapter, FALSE); +} + +/* + * macSetStationEx + * This function is use to set extra MAC station address + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * pMac pointer to mac address buffer (should be 6) + * uIndex index of extra mac address to set + * + * Return(s) + * 0 if success + * negative value if failed + */ +int macSetStationEx(PADAPTER_STRUCT Adapter, UCHAR *pMac, UINT uIndex) +{ +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* do we need to set multicast addr to extra station registers? */ + if (uIndex < MAC_MAX_EXTRA) { + uint32_t uLowAddress, uHighAddress; + + uLowAddress = (*(pMac + 5) | + (*(pMac + 4) << 8) | + (*(pMac + 3) << 16)| + *(pMac + 2) << 24); + + uHighAddress = (*(pMac + 1) | + *pMac << 8); + + /* make sure mac address is not all zero */ + if (uLowAddress | uHighAddress) { + /* enable additional MAC */ + uHighAddress |= DMA_MACENABLE; + KS8695_WRITE_REG(REG_MAC0_LOW + DI.nOffset + uIndex * 8, uLowAddress); + KS8695_WRITE_REG(REG_MAC0_HIGH + DI.nOffset + uIndex * 8, uHighAddress); + return 0; + } + } + + return ~EINVAL; +} + +/* + * macResetStationEx + * This function is use to clear extra MAC station address if set before + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * nIndex index of extra mac address to set + * pMac pointer to mac address buffer (should be 6) + * + * Return(s) + * 0 if success + * negative value if failed + */ +int macResetStationEx(PADAPTER_STRUCT Adapter, UCHAR *pMac) +{ + int i, j; + uint32_t uLowAddress, uHighAddress; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + uLowAddress = (*(pMac + 5) | + (*(pMac + 4) << 8) | + (*(pMac + 3) << 16)| + *(pMac + 2) << 24); + + uHighAddress = (*(pMac + 1) | + *pMac << 8); + + /* set mac enable bit for comparison purpose only! */ + uHighAddress |= DMA_MACENABLE; + + /* if match is found, remove it (set to 0) */ + for (i = 0; i < MAC_MAX_EXTRA; i++) { + j = i * 8; + if (uLowAddress == KS8695_READ_REG(REG_MAC0_LOW + DI.nOffset + j) && + uHighAddress == KS8695_READ_REG(REG_MAC0_HIGH + DI.nOffset + j)) { + KS8695_WRITE_REG(REG_MAC0_LOW + DI.nOffset + j, 0); + KS8695_WRITE_REG(REG_MAC0_HIGH + DI.nOffset + j, 0); + } + } + + return 0; +} + +/* + * macGetIndexStationEx + * This function is use to get the index of empty station + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * nIndex index of empty to use + * negative value if it is full + */ +int macGetIndexStationEx(PADAPTER_STRUCT Adapter) +{ + int i; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + for (i = 0; i < MAC_MAX_EXTRA; i++) { + if (!(KS8695_READ_REG(REG_MAC0_HIGH + DI.nOffset + i * 8) & DMA_MACENABLE)) { + return i; + } + } + + DRV_WARN("%s: no empty slot for Additional Station Address", __FUNCTION__); + return -1; +} + +/* Interrupt Bit definitions */ +#define IB_WAN_LINK 31 +#define IB_WAN_RX_STOPPED 25 +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) +#define IB_HPNA_TX 23 +#define IB_HPNA_RX_STOPPED 18 +#endif +#define IB_LAN_TX 17 +#define IB_LAN_RX_STOPPED 12 + +/* + * macConfigureInterrupt + * This routine is used to configure interrupt priority + * + * Inputs: + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Returns: + * NONE + */ +void macConfigureInterrupt(PADAPTER_STRUCT Adapter) +{ + int i; + UINT uIMR, uIPR = 0; + unsigned long flags; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + spin_lock_irqsave(&DI.lock, flags); + /*spin_lock(&DI.lock);*/ + uIMR = KS8695_READ_REG(KS8695_INT_CONTL); + switch (DI.usDMAId) { + case DMA_LAN: + for (i = IB_LAN_RX_STOPPED; i <= IB_LAN_TX; i++) { + if (stDMAIntCfg[i].bFIQ) { + uIMR |= (1L << i); + DI.bUseFIQ = TRUE; + } + else { + uIMR &= ~(1L << i); + uIPR |= ((UINT)(stDMAIntCfg[i].byPriority) & 0xf) << (i - IB_LAN_RX_STOPPED + 1) * 4; + } + } + KS8695_WRITE_REG(KS8695_INT_LAN_PRIORITY, uIPR); + break; + +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + for (i = IB_HPNA_RX_STOPPED; i <= IB_HPNA_TX; i++) { + if (stDMAIntCfg[i].bFIQ) { + uIMR |= (1L << i); + DI.bUseFIQ = TRUE; + } + else { + uIMR &= ~(1L << i); + uIPR |= ((UINT)(stDMAIntCfg[i].byPriority) & 0xf) << (i - IB_HPNA_RX_STOPPED + 1) * 4; + } + } + KS8695_WRITE_REG(KS8695_INT_HPNA_PRIORITY, uIPR); + break; +#endif + + case DMA_WAN: + default: + for (i = IB_WAN_RX_STOPPED; i <= IB_WAN_LINK; i++) { + if (stDMAIntCfg[i].bFIQ) { + uIMR |= (1L << i); + DI.bUseFIQ = TRUE; + } + else { + uIMR &= ~(1L << i); + uIPR |= ((UINT)(stDMAIntCfg[i].byPriority) & 0xf) << (i - IB_WAN_RX_STOPPED + 1) * 4; + } + } + KS8695_WRITE_REG(KS8695_INT_WAN_PRIORITY, uIPR); + break; + } + KS8695_WRITE_REG(KS8695_INT_CONTL, uIMR); + /*spin_unlock(&DI.lock);*/ + spin_unlock_irqrestore(&DI.lock, flags); +} + +/* + * macEnableInterrupt + * This routine is used to enable/disable interrupt related to MAC only + * + * Inputs: + * Adapter pionter to ADAPTER_STRUCT data structure. + * bEnable enable/disable interrupt + * + * Returns: + * NONE + */ +void macEnableInterrupt(PADAPTER_STRUCT Adapter, BOOLEAN bEnable) +{ + UINT uIER; + + spin_lock(&DI.lock); + uIER = KS8695_READ_REG(KS8695_INT_ENABLE); + switch (DI.usDMAId) { + case DMA_LAN: +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: +#endif + if (bEnable) + uIER |= DI.uIntMask; + else + uIER &= ~DI.uIntMask; + break; + + case DMA_WAN: + if (bEnable) + uIER |= (DI.uIntMask | DI.uLinkIntMask); + else + uIER &= ~(DI.uIntMask | DI.uLinkIntMask); + break; + + default: + DRV_INFO("unsupported option"); + break; + } + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER); + spin_unlock(&DI.lock); + ks8695_power_saving(bEnable); +} + +/* + * macGetStationAddress + * This function reads MAC address from station address registers. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * pMacAddress pointer to a byte array to hold MAC address (at least 6 bytes long) + * + * Return(s) + * NONE. + */ +void macGetStationAddress(PADAPTER_STRUCT Adapter, uint8_t *pMacAddress) +{ + UINT32 uTmp; + int i; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* read low 4 buytes, byte order (e.g. in our NIC card, 00101a00000d) */ + uTmp = KS8695_READ_REG(REG_STATION_LOW + DI.nOffset); + for (i = (MAC_ADDRESS_LEN - 1); i > 1; i--) + { + pMacAddress[i] = (UCHAR)(uTmp & 0x0ff); + uTmp >>= 8; + } + /* read high 2 bytes */ + uTmp = KS8695_READ_REG(REG_STATION_HIGH + DI.nOffset); + pMacAddress[1] = (UCHAR)(uTmp & 0x0ff); + uTmp >>= 8; + pMacAddress[0] = (UCHAR)(uTmp & 0x0ff); +} + +/* + * macSetStationAddress + * This function sets MAC address to given type (WAN, LAN or HPHA) + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * pMacAddress pointer to a byte array to hold MAC address (at least 6 bytes long) + * + * Return(s) + * NONE. + */ +void macSetStationAddress(PADAPTER_STRUCT Adapter, uint8_t *pMacAddress) +{ + UINT32 uLow, uHigh; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + uLow = ((UINT32)pMacAddress[2] << 24); + uLow += ((UINT32)pMacAddress[3] << 16); + uLow += ((UINT32)pMacAddress[4] << 8); + uLow += pMacAddress[5]; + uHigh = ((UINT32)pMacAddress[0] << 8) + pMacAddress[1]; + KS8695_WRITE_REG(REG_STATION_LOW + DI.nOffset, uLow); + KS8695_WRITE_REG(REG_STATION_HIGH + DI.nOffset, uHigh); +} + +/* + * swConfigurePort + * This function is used to configure a give port for LAN. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * uPort port to start + * + * Return(s) + * NONE. + */ +void swConfigurePort(PADAPTER_STRUCT Adapter, UINT uPort) +{ + UINT uReg, uOff; + BOOLEAN bPort5 = FALSE; + + if (uPort >= SW_MAX_LAN_PORTS) { + if (SW_MAX_LAN_PORTS == uPort) { + /* port 5 */ + bPort5 = TRUE; + } + else { + /* out of range */ + DRV_INFO("%s: port %d to configure out of range", __FUNCTION__, uPort); + return; + } + } +#ifndef CONFIG_ARCH_KS8695P + uOff = KS8695_SWITCH_PORT1 + uPort * 4; +#else + if (bPort5) + uOff = KS8695_SEP5C1; + else + uOff = KS8695_SEP1C1 + uPort * 0x0c; +#endif + + uReg = 0; + uReg |= (UINT)DPI[uPort].usTag << 16; + + if (!bPort5) { + /* connection media type */ + /*uReg &= ~(SW_PORT_DISABLE_AUTONEG | SW_PORT_100BASE | SW_PORT_FULLDUPLEX);*/ + if (SW_PHY_AUTO != DI.usCType[uPort]) { + uReg |= SW_PORT_DISABLE_AUTONEG; + if (SW_PHY_100BASE_TX == DI.usCType[uPort] || + SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) { + uReg |= SW_PORT_100BASE; + } + if (SW_PHY_10BASE_T_FD == DI.usCType[uPort] || + SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) { + uReg |= SW_PORT_FULLDUPLEX; + } + } + } + else { + /* Rx direct mode */ + if (DI.bRxDirectMode) { + uReg |= SW_PORT_RX_DIRECT_MODE; + } + /* Tx Pre-tag mode */ + if (DI.bTxRreTagMode) { + uReg |= SW_PORT_TX_PRETAG_MODE; + } + } + + /* cross talk bit mask */ + uReg |= ((UINT)(DPI[uPort].byCrossTalkMask & 0x1f)) << 8; + + /* spanning tree */ + if (SW_SPANNINGTREE_ALL == DPI[uPort].bySpanningTree) { + uReg |= SW_PORT_TX_SPANNINGTREE | SW_PORT_RX_SPANNINGTREE; + } + else { + if (SW_SPANNINGTREE_TX == DPI[uPort].bySpanningTree) { + uReg |= SW_PORT_TX_SPANNINGTREE; + } + if (SW_SPANNINGTREE_RX == DPI[uPort].bySpanningTree) { + uReg |= SW_PORT_RX_SPANNINGTREE; + } + } + if (DPI[uPort].byDisableSpanningTreeLearn) { + uReg |= SW_PORT_NO_SPANNINGTREE; + } + /* ingress broadcast storm protection */ + if (DPI[uPort].byStormProtection) { + uReg |= SW_PORT_STORM_PROCTION; + } + /* ingress priority */ + if (DPI[uPort].byIngressPriority) { + uReg |= SW_PORT_HI_PRIORITY; + } + if (DPI[uPort].byIngressPriorityTOS) { + uReg |= SW_PORT_TOS_ENABLE; + } + if (DPI[uPort].byIngressPriority802_1P) { + uReg |= SW_PORT_8021Q_ENABLE; + } + /* egress priority */ + if (DPI[uPort].byEgressPriority) { + uReg |= SW_PORT_PRIOTIRY_ENABLE; + } + KS8695_WRITE_REG(uOff, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + +#ifdef DEBUG_THIS + DRV_INFO("%s: uOff=0x%08x, reg=0x%08x", __FUNCTION__, uOff, uReg); +#endif +} + +/* + * swEnableSwitch + * This function is used to enable/disable switch + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * enable enable/disable switch + * + * Return(s) + * NONE. + */ +void swEnableSwitch(PADAPTER_STRUCT Adapter, UINT enable) +{ + UINT uReg; + + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + if (enable) { + uReg |= SW_CTRL0_SWITCH_ENABLE; + /* for debug purpose */ + /*uReg |= 0x00080000;*/ + } else { + uReg &= ~SW_CTRL0_SWITCH_ENABLE; + /* for debug purpose */ + /*uReg &= ~0x00080000;*/ + } + + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * swReadSNMPReg + * This function is used to read SNMP registers + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uIndex index of SNMP register to read + * + * Return(s) + * value read + */ +UINT swReadSNMPReg(PADAPTER_STRUCT Adapter, UINT uIndex) +{ +#ifndef CONFIG_ARCH_KS8695P + UINT uValue, uTimeout = 0; + + if (uIndex >= 512) + uIndex = 511; + + KS8695_WRITE_REG(KS8695_MANAGE_COUNTER, uIndex); + DelayInMicroseconds(10); + do { + uValue = KS8695_READ_REG(KS8695_MANAGE_DATA); + if (uValue & SW_SNMP_DATA_VALID) { + if (uValue & SW_SNMP_DATA_OVERFLOW) { + KS8695_WRITE_REG(KS8695_MANAGE_DATA, SW_SNMP_DATA_OVERFLOW); + } + /* clear status bits */ + uValue &= 0x3fffffff; + return uValue; + } + DelayInMilliseconds(1); + } + while (uTimeout++ < 2000); + + if (uValue & SW_SNMP_DATA_OVERFLOW) { + KS8695_WRITE_REG(KS8695_MANAGE_DATA, SW_SNMP_DATA_OVERFLOW); + } +#else + u32 reg, value, timeout = 0; + + reg = KS8695_SEIAC_READ | KS8695_SEIAC_TAB_MIB | (KS8695_SEIAC_INDEX_MASK & uIndex); + do { + KS8695_WRITE_REG(KS8695_SEIAC, reg); + DelayInMicroseconds(10); + + value = KS8695_READ_REG(KS8695_SEIADL); + if (value & SW_SNMP_DATA_VALID) { + if (value & SW_SNMP_DATA_OVERFLOW) { + reg = KS8695_SEIAC_WRITE | KS8695_SEIAC_TAB_MIB | (KS8695_SEIAC_INDEX_MASK & uIndex); + KS8695_WRITE_REG(KS8695_SEIAC, reg); + } + /* clear status bits */ + value &= 0x3fffffff; + return value; + } + } + while (timeout++ < 2000); + + printk("%s: timeout\n", __FUNCTION__); +#endif + return 0; +} + +/* + * swConfigure + * This function is used to config switch engine. It is assume that + * the BIST is performed already (by boot loader). + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE + */ +void swConfigure(PADAPTER_STRUCT Adapter) +{ + UINT uReg, i; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + if (DMA_LAN == DI.usDMAId) { + /* read switch control 0 register */ + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + /* flow control for LAN ports */ + if (DI.bPort5FlowCtrl) + { + /* flow control for port 5 */ + uReg |= SW_CTRL0_ENABLE_PORT5; + } + else { + uReg &= ~SW_CTRL0_ENABLE_PORT5; + } +#ifndef CONFIG_ARCH_KS8695P + if (DI.bPortsFlowCtrl) + { + /* four flow control for each LAN port */ + uReg |= SW_CTRL0_ENABLE_PORTS; + } + else { + uReg &= ~SW_CTRL0_ENABLE_PORTS; + } +#else +#if 0 + /* RLQ, need to verify */ + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + forceFlowControl(Adapter, i, DI.bPortsFlowCtrl); + //if (!DI.bPortsFlowCtrl) + // backPressureEnable(Adapter, i, DI.bPortsFlowCtrl); + backPressureEnable(Adapter, i, TRUE); + } +#endif +#endif + + /*RLQ, 11/20/2002, requested by Hock, backpressure will fix packet + * drop problem in half duplex mode + */ + uReg |= 0x00000020; /* bit 5 */ + + /* set flow control fairness mode based on LAN flow control settings, should use */ + + /* read switch control 0 register */ + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + + /* configure LAN port 1-4 and Port 5 */ + for (i = 0; i <= SW_MAX_LAN_PORTS; i++) + swConfigurePort(Adapter, i); + } + else { + DRV_INFO("%s: type (%x) not supported", __FUNCTION__, DI.usDMAId); + } +} + +/* + * swSetLED + * This function is used to set given LED + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * bLED1 TRUE for LED1 and FALSE for LED0 + * nSel emum type LED_SELECTOR + * + * Return(s) + * NONE. + */ +void swSetLED(PADAPTER_STRUCT Adapter, BOOLEAN bLED1, LED_SELECTOR nSel) +{ + UINT32 uReg; + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* there is no LED for HPNA */ + break; +#endif + + case DMA_WAN: + uReg = KS8695_READ_REG(KS8695_WAN_CONTROL); + if (bLED1) { + uReg &= 0xffffff8f; /* 6:4 */ + uReg |= (UINT)(nSel & 0x07) << 4; + } + else { + uReg &= 0xfffffff8; /* 2:0 */ + uReg |= (UINT)(nSel & 0x07); + } + KS8695_WRITE_REG(KS8695_WAN_CONTROL, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + return; + + default: + case DMA_LAN: + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + if (bLED1) { + uReg &= 0xf1ffffff; /* 27:25 */ + uReg |= (UINT)(nSel & 0x07) << 25; + } + else { + uReg &= 0xfe3fffff; /* 24:22 */ + uReg |= (UINT)(nSel & 0x07) << 22; + } + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + break; + } +} + +/* + * swAutoNegoStart + * This function is used to start auto negotiation process + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * uPort port to start + * + * Return(s) + * NONE. + */ +void swAutoNegoStart(PADAPTER_STRUCT Adapter, UINT uPort) +{ + UINT uReg, uOff, uShift = 0; + +#ifdef DEBUG_THIS + DRV_INFO("%s: port=%d, bAutoNegoInProgress=%d", __FUNCTION__, uPort, DI.bAutoNegoInProgress[uPort]); +#endif + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* there is no auto nego for HPNA */ + return; +#endif + + case DMA_WAN: + uOff = KS8695_WAN_CONTROL; + uShift = 16; + break; + + default: + case DMA_LAN: + switch (uPort) { + case SW_PORT_4: + uOff = KS8695_SWITCH_AUTO1; + uShift = 16; + break; + + case SW_PORT_3: + uOff = KS8695_SWITCH_AUTO1; + break; + + case SW_PORT_2: + uOff = KS8695_SWITCH_AUTO0; + uShift = 16; + break; + + case SW_PORT_1: + default: + uOff = KS8695_SWITCH_AUTO0; + break; + } + break; + } + + /* if not auto nego */ + if (SW_PHY_AUTO != DI.usCType[uPort]) { + return; + } + DI.bAutoNegoInProgress[uPort] = TRUE; + uReg = KS8695_READ_REG(uOff); + uReg |= ((UINT)SW_AUTONEGO_RESTART << uShift); + KS8695_WRITE_REG(uOff, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * swAutoNegoAdvertisement + * This function is used to set PHY Advertisement. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to advertise + * + * Return(s) + * NONE + */ +void swAutoNegoAdvertisement(PADAPTER_STRUCT Adapter, UINT uPort) +{ + UINT uReg, uOff, uShift = 0; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* there is no auto nego feature for HPNA DMA, but I'll assume that + if SW_PHY_AUTO is set, use 100/FD as default + */ + uReg = KS8695_READ_REG(KS8695_MISC_CONTROL) & 0xfffffffc; + if (SW_PHY_AUTO == DI.usCType[uPort]) { + uReg |= 0x00000003; + } + else { + if (SW_PHY_100BASE_TX == DI.usCType[uPort] || + SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) { + uReg |= 0x00000002; + } + if (SW_PHY_10BASE_T_FD == DI.usCType[uPort] || + SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) { + uReg |= 0x00000001; + } + } + KS8695_WRITE_REG(REG_MISC_CONTROL, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + return; +#endif + + case DMA_WAN: + uOff = KS8695_WAN_CONTROL; + uShift = 16; + break; + + default: + case DMA_LAN: + switch (uPort) { + case SW_PORT_4: + uOff = KS8695_SWITCH_AUTO1; + break; + + case SW_PORT_3: + uOff = KS8695_SWITCH_AUTO1; + uShift = 16; + break; + + case SW_PORT_2: + uOff = KS8695_SWITCH_AUTO0; + break; + + case SW_PORT_1: + default: + uOff = KS8695_SWITCH_AUTO0; + uShift = 16; + break; + } + break; + } + uReg = KS8695_READ_REG(uOff); + /* clear corresponding bits first */ + uReg &= ~(SW_AUTONEGO_ADV_MASK << uShift); + if (SW_PHY_AUTO == DI.usCType[uPort]) + { + uReg |= (SW_AUTONEGO_ADV_100FD | SW_AUTONEGO_ADV_100HD | + SW_AUTONEGO_ADV_10FD | SW_AUTONEGO_ADV_10HD) << uShift; + } + else + { + /* Manually set */ + switch (DI.usCType[uPort]) + { + case SW_PHY_100BASE_TX_FD: + uReg |= SW_AUTONEGO_ADV_100FD << uShift; + break; + + case SW_PHY_100BASE_TX: + uReg |= SW_AUTONEGO_ADV_100HD << uShift; + break; + + case SW_PHY_10BASE_T_FD: + uReg |= SW_AUTONEGO_ADV_10FD << uShift; + break; + + case SW_PHY_10BASE_T: + uReg |= SW_AUTONEGO_ADV_10HD << uShift; + break; + + default: + /* Unsupported media type found! */ + DRV_WARN("%s> Unsupported media type found!", __FUNCTION__); + return; + } + } + + if (DI.bRxFlowCtrl) + uReg |= SW_AUTONEGO_ADV_PUASE << uShift; + + uReg &= ~((UINT)SW_AUTONEGO_RESTART << uShift); + KS8695_WRITE_REG(uOff, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * swGetWANLinkStatus + * This function is used to get WAN link status. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to query + * + * Return(s) + * TRUE if link is up + * FALSE if link is down + */ +BOOLEAN swGetWANLinkStatus(PADAPTER_STRUCT Adapter) +{ + UINT uReg; + + uReg = KS8695_READ_REG(KS8695_WAN_CONTROL); + /* if not linked yet */ + if (!(uReg & ((UINT)SW_AUTONEGO_STAT_LINK << 16))) { +#ifdef DEBUG_THIS + DRV_INFO("WAN link is down"); +#endif + return FALSE; + } +#ifdef DEBUG_THIS + DRV_INFO("WAN link is up"); +#endif + + return TRUE; +} + +/* + * swGetPhyStatus + * This function is used to get the status of auto negotiation. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to query + * + * Return(s) + * TRUE if connected + * FALSE otherwise + */ +int swGetPhyStatus(PADAPTER_STRUCT Adapter, UINT uPort) +{ + UINT uReg, uOff, uShift = 0; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* temp */ + uReg = KS8695_READ_REG(REG_MISC_CONTROL); + DI.usLinkSpeed[uPort] = (uReg & 0x00000002) ? SPEED_100 : SPEED_10; + DI.bHalfDuplex[uPort] = (uReg & 0x00000001) ? FULL_DUPLEX : HALF_DUPLEX; + /* note that there is no register bit corresponding to HPNA's link status + therefore don't report it */ + DI.bLinkActive[uPort] = TRUE; + return TRUE; +#endif + + case DMA_WAN: + uOff = KS8695_WAN_CONTROL; + uShift = 16; + break; + + default: + case DMA_LAN: + switch (uPort) { + case SW_PORT_4: + uOff = KS8695_SWITCH_AUTO1; + break; + + case SW_PORT_3: + uOff = KS8695_SWITCH_AUTO1; + uShift = 16; + break; + + case SW_PORT_2: + uOff = KS8695_SWITCH_AUTO0; + break; + + case SW_PORT_1: + default: + uOff = KS8695_SWITCH_AUTO0; + uShift = 16; + break; + } + } + + uReg = KS8695_READ_REG(uOff); + /* if not linked yet */ + if (!(uReg & ((UINT)SW_AUTONEGO_STAT_LINK << uShift))) { + DI.bLinkActive[uPort] = FALSE; + DI.usLinkSpeed[uPort] = SPEED_UNKNOWN; + DI.bHalfDuplex[uPort] = 0; + gpioSet(Adapter, uPort, FALSE); + return FALSE; + } + DI.bLinkActive[uPort] = TRUE; + if (SW_PHY_AUTO == DI.usCType[uPort]) { + /* if auto nego complete */ + //RLQ, 12/18/2003, bug + if (uReg & ((UINT)SW_AUTONEGO_COMPLETE << uShift)) { + /* clear auto nego restart bit */ + uReg &= ~((UINT)SW_AUTONEGO_RESTART << uShift); + KS8695_WRITE_REG(uOff, uReg); + DelayInMicroseconds(10); + + DI.usLinkSpeed[uPort] = (uReg & ((UINT)SW_AUTONEGO_STAT_SPEED << uShift)) ? SPEED_100 : SPEED_10; + DI.bHalfDuplex[uPort] = (uReg & ((UINT)SW_AUTONEGO_STAT_DUPLEX << uShift)) ? FULL_DUPLEX : HALF_DUPLEX; + DI.bAutoNegoInProgress[uPort] = FALSE; + + gpioSet(Adapter, uPort, SPEED_100 == DI.usLinkSpeed[uPort]); + /*RLQ, need to verify real duplex mode instead report it correct here */ + /* duplex bit may not right if partner doesn't support all mode, do further detection */ + if ((uReg & (SW_AUTONEGO_PART_100FD | SW_AUTONEGO_PART_100HD | SW_AUTONEGO_PART_10FD | SW_AUTONEGO_PART_10HD) << uShift) + != (SW_AUTONEGO_PART_100FD | SW_AUTONEGO_PART_100HD | SW_AUTONEGO_PART_10FD | SW_AUTONEGO_PART_10HD)) { + if (SPEED_100 == DI.usLinkSpeed[uPort]) { + if ((uReg & (SW_AUTONEGO_PART_100FD << uShift))) { + DI.bHalfDuplexDetected[uPort] = FULL_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, TRUE); + backPressureEnable(Adapter, uPort, FALSE); +#endif + } else { + DI.bHalfDuplexDetected[uPort] = HALF_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, FALSE); + backPressureEnable(Adapter, uPort, TRUE); +#endif + } + } + else { + if ((uReg & (SW_AUTONEGO_PART_10FD << uShift))) { + DI.bHalfDuplexDetected[uPort] = FULL_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, TRUE); + backPressureEnable(Adapter, uPort, FALSE); +#endif + } + else { + DI.bHalfDuplexDetected[uPort] = HALF_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, FALSE); + backPressureEnable(Adapter, uPort, TRUE); +#endif + } + } + } + + /* software workaround for flow control, need to know partner's flow control */ + if (DMA_WAN == DI.usDMAId) { /* currently do it to WAN only, there is no problem to LAN, will do HPNA later */ + uint8_t bFlowCtrl; + + /* we need to check partner's control flow setting for the matching, if not, changes ours */ + bFlowCtrl = ((SW_AUTONEGO_PART_PAUSE << uShift) & uReg) ? TRUE : FALSE; + if (bFlowCtrl != DI.bRxFlowCtrl) { /* Tx same as Rx, so test Rx should be enough */ + /* need to change ours accordingly, which will overwrite current one */ + macConfigureFlow(Adapter, bFlowCtrl); + } + } +#ifdef DEBUG_THIS + DRV_INFO("%s> Auto Nego completed", __FUNCTION__); +#endif + } + else { +#ifdef DEBUG_THIS + /* auto nego in progress */ + DRV_INFO("%s> Auto Nego in progress...", __FUNCTION__); +#endif + /* wait for next timer */ + DI.bLinkActive[uPort] = FALSE; + DI.usLinkSpeed[uPort] = SPEED_UNKNOWN; + DI.bHalfDuplex[uPort] = 0; + } + } + else { +#ifdef DEBUG_THIS + DRV_INFO("%s: media type=%d, port=%d", __FUNCTION__, DI.usCType[uPort], uPort); +#endif + + /* manually connection */ + if (SW_PHY_10BASE_T_FD == DI.usCType[uPort] || SW_PHY_100BASE_TX_FD == DI.usCType[uPort]) { + DI.bHalfDuplex[uPort] = FULL_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, TRUE); + backPressureEnable(Adapter, uPort, FALSE); +#endif + } + else { + DI.bHalfDuplex[uPort] = HALF_DUPLEX; +#ifdef CONFIG_ARCH_KS8695P + forceFlowControl(Adapter, uPort, FALSE); + backPressureEnable(Adapter, uPort, TRUE); +#endif + } + if (SW_PHY_100BASE_TX_FD == DI.usCType[uPort] || SW_PHY_100BASE_TX == DI.usCType[uPort]) { + DI.usLinkSpeed[uPort] = SPEED_100; + gpioSet(Adapter, uPort, TRUE); + } + else { + DI.usLinkSpeed[uPort] = SPEED_10; + gpioSet(Adapter, uPort, FALSE); + } + + /* software workaround for flow control, need to know partner's flow control */ + if (DMA_WAN == DI.usDMAId) { /* currently do it to WAN only, there is no problem to LAN, will do HPNA later */ + macConfigureFlow(Adapter, FULL_DUPLEX == DI.bHalfDuplex[uPort] ? TRUE : FALSE); + } + } + return TRUE; +} + +/* + * swDetectPhyConnection + * This function is used to start auto negotiation + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * uPort port to start + * + * Return(s) + * NONE. + */ +void swDetectPhyConnection(PADAPTER_STRUCT Adapter, UINT uPort) +{ + /*if (SW_PHY_AUTO == DI.usCType[uPort] && !DI.bAutoNegoInProgress[uPort] && DI.bLinkChanged[uPort]) {*/ + if (LINK_SELECTION_FORCED != DI.byDisableAutoNego[uPort] && !DI.bAutoNegoInProgress[uPort] && DI.bLinkChanged[uPort]) { + swAutoNegoStart(Adapter, uPort); + DI.bLinkChanged[uPort] = FALSE; + DI.bLinkActive[uPort] = FALSE; + } + swGetPhyStatus(Adapter, uPort); +} + +/* + * swPhyReset + * This function is used to reset phy chipset (powerdown or soft reset). + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to start + * + * Return(s) + * NONE + */ +void swPhyReset(PADAPTER_STRUCT Adapter, UINT uPort) +{ + UINT uReg, uShift = 0; + UINT uPowerReg; + /*RLQ, workaround */ + UINT uReg1; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* IEEE spec. of auto nego bit */ + uReg1 = BIT(7); + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + return; +#endif + + case DMA_WAN: + uPowerReg = KS8695_WAN_POWERMAGR; + break; + + default: + case DMA_LAN: + switch (uPort) { + case SW_PORT_4: + uPowerReg = KS8695_LAN34_POWERMAGR; + break; + + case SW_PORT_3: + uPowerReg = KS8695_LAN34_POWERMAGR; + uShift = 16; + break; + + case SW_PORT_2: + uPowerReg = KS8695_LAN12_POWERMAGR; + break; + + case SW_PORT_1: + default: + uPowerReg = KS8695_LAN12_POWERMAGR; + uShift = 16; + break; + } + } + + if (DI.bPowerDownReset) { + int nCount = 0; + + uReg = KS8695_READ_REG(uPowerReg); + KS8695_WRITE_REG(uPowerReg, uReg | ((UINT)POWER_POWERDOWN << uShift)); + /* need 20 cpu clock delay for switch related registers */ + /*DelayInMicroseconds(10);*/ + do { + DelayInMilliseconds(50); + } while (nCount++ < 4); + uReg &= ~((UINT)POWER_POWERDOWN << uShift); + /* turn off IEEE auto nego */ + uReg &= ~(uReg1 << uShift); + KS8695_WRITE_REG(uPowerReg, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + else { + uReg = KS8695_READ_REG(uPowerReg); + /* turn off IEEE auto nego */ + uReg &= ~(uReg1 << uShift); + KS8695_WRITE_REG(uPowerReg, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } +} + +/* + * swConfigureMediaType + * This function is used to set linke media type (forced) + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to start + * uSpeed media speed to set + * uDuplex media duplex to set + * + * Return(s) + * TRUE if succeeded + * FALSE otherwise + */ +void swConfigureMediaType(PADAPTER_STRUCT Adapter, UINT uPort, UINT uSpeed, UINT uDuplex) +{ + UINT32 uReg, uOffset; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* there is no way to force HPNA */ + return; +#endif + + case DMA_WAN: + uOffset = KS8695_WAN_CONTROL; + uPort = 0; + break; + + default: + case DMA_LAN: + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s: port (%d) gave is out of range", __FUNCTION__, uPort); + return; + } +#ifndef CONFIG_ARCH_KS8695P + uOffset = KS8695_SWITCH_PORT1 + uPort * 4; +#else + if (SW_MAX_LAN_PORTS == uPort) + uOffset = KS8695_SEP5C1; + else + uOffset = KS8695_SWITCH_PORT1 + uPort * 0x0c; +#endif + break; + } + + uReg = KS8695_READ_REG(uOffset); + /* clear corresponding bits first */ + uReg &= 0xFFFF1FFF; + if (LINK_SELECTION_FORCED == DI.byDisableAutoNego[uPort]) { + uReg |= SW_PORT_DISABLE_AUTONEG; + /* force to half duplex */ + DI.bRxFlowCtrl = FALSE; + DI.bTxFlowCtrl = FALSE; + if (uSpeed) { + uReg |= SW_PORT_100BASE; + if (uDuplex) { + uReg |= SW_PORT_FULLDUPLEX; + DI.usCType[uPort] = SW_PHY_100BASE_TX_FD; + } + else { + DI.usCType[uPort] = SW_PHY_100BASE_TX; + } + } + else { + if (uDuplex) { + uReg |= SW_PORT_FULLDUPLEX; + DI.usCType[uPort] = SW_PHY_10BASE_T_FD; + } + else { + DI.usCType[uPort] = SW_PHY_10BASE_T; + } + } + } + else { + if (DMA_WAN == DI.usDMAId) { + DI.bRxFlowCtrl = FLOWCONTROL_DEFAULT; + DI.bTxFlowCtrl = FLOWCONTROL_DEFAULT; + } + if (LINK_SELECTION_FULL_AUTO == DI.byDisableAutoNego[uPort]) { + DI.usCType[uPort] = SW_PHY_AUTO; + } else { + switch (uSpeed) { + case 0: + if (uDuplex) + DI.usCType[uPort] = SW_PHY_10BASE_T_FD; /* 10Base-TX Full Duplex */ + else { + /* don't advertise flow control in half duplex case */ + if (DMA_WAN == DI.usDMAId) { + DI.bRxFlowCtrl = FALSE; + DI.bTxFlowCtrl = FALSE; + } + DI.usCType[uPort] = SW_PHY_10BASE_T; /* 10Base-T Half Duplex */ + } + break; + + case 1: + default: + if (uDuplex) + DI.usCType[uPort] = SW_PHY_100BASE_TX_FD; /* 100Base-TX Full Duplex */ + else { + /* don't advertise flow control in half duplex case */ + if (DMA_WAN == DI.usDMAId) { + DI.bRxFlowCtrl = FALSE; + DI.bTxFlowCtrl = FALSE; + } + DI.usCType[uPort] = SW_PHY_100BASE_TX; /* 100Base-TX Half Duplex */ + } + break; + } + } + } + + KS8695_WRITE_REG(uOffset, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +#ifdef DEBUG_THIS + DRV_INFO("%s: media type=%d, offset=0x%08x, port=%d", __FUNCTION__, DI.usCType[uPort], uOffset, uPort); +#endif + + DI.bLinkChanged[uPort] = TRUE; + DI.bLinkActive[uPort] = FALSE; /* watchdog routine will check link status if reset this variable!!! */ + swPhyReset(Adapter, uPort); + swAutoNegoAdvertisement(Adapter, uPort); + swDetectPhyConnection(Adapter, uPort); +} + +/* + * swPhyLoopback + * This function is used to set loopback in PHY layer. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uPort port to start + * bLoopback indicates loopback enable or not + * + * Return(s) + * TRUE if succeeded + * FALSE otherwise + */ +BOOLEAN swPhyLoopback(PADAPTER_STRUCT Adapter, UINT uPort, BOOLEAN bLoopback) +{ + UINT uReg, uOff, uShift = 0; + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + return FALSE; +#endif + + case DMA_WAN: + uOff = KS8695_WAN_POWERMAGR; + uShift = 0; + break; + + default: + case DMA_LAN: + switch (uPort) { + case SW_PORT_4: + uOff = KS8695_LAN34_POWERMAGR; + break; + + case SW_PORT_3: + uOff = KS8695_LAN34_POWERMAGR; + uShift = 16; + break; + + case SW_PORT_2: + uOff = KS8695_LAN12_POWERMAGR; + break; + + case SW_PORT_1: + default: + uOff = KS8695_LAN12_POWERMAGR; + uShift = 16; + break; + } + } + + uReg = KS8695_READ_REG(uOff); + if (bLoopback) + uReg |= ((UINT)POWER_LOOPBACK << uShift); + else + uReg &= ~((UINT)POWER_LOOPBACK << uShift); + KS8695_WRITE_REG(uOff, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + + return TRUE; +} + +/* + * swGetMacAddress + * This function is use to get switch engine Mac address and store it in stSwitchMac. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void swGetMacAddress(PADAPTER_STRUCT Adapter) +{ + UINT32 uTmp; + int i; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + uTmp = KS8695_READ_REG(KS8695_SWITCH_MAC_LOW); + for (i = (MAC_ADDRESS_LEN - 1); i > 1; i--) + { + DI.stSwitchMac[i] = (UCHAR)(uTmp & 0x0ff); + uTmp >>= 8; + } + /* read high 2 bytes */ + uTmp = KS8695_READ_REG(KS8695_SWITCH_MAC_HIGH); + DI.stSwitchMac[1] = (UCHAR)(uTmp & 0x0ff); + uTmp >>= 8; + DI.stSwitchMac[0] = (UCHAR)(uTmp & 0x0ff); +} + +/* + * swSetMacAddress + * This function is use to set switch engine Mac address. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * pMac pointer to mac address buffer (should be 6) + * + * Return(s) + * NONE + */ +void swSetMacAddress(PADAPTER_STRUCT Adapter, UCHAR *pMac) +{ + uint32_t uLowAddress, uHighAddress; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + memcpy(&DI.stSwitchMac, pMac, MAC_ADDRESS_LEN); + uLowAddress = (*(pMac + 5) | + (*(pMac + 4) << 8) | + (*(pMac + 3) << 16)| + *(pMac + 3) << 24); + + uHighAddress = (*(pMac + 1) | + *pMac << 8); + + KS8695_WRITE_REG(KS8695_SWITCH_MAC_LOW, uLowAddress); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + KS8695_WRITE_REG(KS8695_SWITCH_MAC_HIGH, uHighAddress); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * swResetSNMPInfo + * This function is use to get SNMP counters information + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void swResetSNMPInfo(PADAPTER_STRUCT Adapter) +{ + memset(&Adapter->net_stats, 0, sizeof(Adapter->net_stats)); +} + +/* + * swCreateLookUpTable + * This function is use to create loopup table. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void swCreateLookUpTable(PADAPTER_STRUCT Adapter) +{ + unsigned int mac = 0, index = 0, tmp = 0, portmap = 0; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + mac = 0x01020304; + portmap = 0x10000; + +#ifndef CONFIG_ARCH_KS8695P + for (index=0; index<5; index++) + { + KS8695_WRITE_REG(KS8695_SWITCH_LUE_HIGH, 0x200000 + (portmap << index)); + DelayInMicroseconds(10); + + KS8695_WRITE_REG(KS8695_SWITCH_LUE_LOW, mac++); + DelayInMicroseconds(10); + + KS8695_WRITE_REG(KS8695_SWITCH_LUE_CTRL, index); + DelayInMicroseconds(10); + + do + { + tmp = KS8695_READ_REG(KS8695_SWITCH_LUE_CTRL) & 0x1000; + } while (tmp); + } +#else + index = index; /* no complain pls */ + /* the user can program other MAC addresses for static table */ + tmp = 0x0002; /* e.g. this is the MAC high and low addr for the notebook I am using for test */ + mac = 0xa55d1590; + + KS8695_WRITE_REG(KS8695_SEIAC, + KS8695_SEIAC_WRITE | KS8695_SEIAC_TAB_STATIC | (KS8695_SEIAC_INDEX_MASK & index)); + DelayInMicroseconds(10); + + KS8695_WRITE_REG(KS8695_SEIADH1, 0x200000 + (portmap << index) + tmp); + DelayInMicroseconds(10); + + KS8695_WRITE_REG(KS8695_SEIADL, mac); + DelayInMicroseconds(10); +#endif +} + +/* + * swConfigTagRemoval + * This function is use to configure tag removal for ingress to given port. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port for the tag to insert + * bRemoval enable/disable removal + * + * Return(s) + * NONE + */ +void swConfigTagRemoval(PADAPTER_STRUCT Adapter, UINT uPort, UINT bRemoval) +{ + uint32_t uReg; + + uReg = KS8695_READ_REG(KS8695_SWITCH_ADVANCED); + if (bRemoval) { + uReg |= (1L << (22 + uPort)); + } + else { + uReg &= ~(1L << (22 + uPort)); + } + KS8695_WRITE_REG(KS8695_SWITCH_ADVANCED, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * swConfigTagInsertion + * This function is use to configure tag insertion for engress to given port. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port for the tag to insert + * bInsert enable/disable insertion + * + * Return(s) + * NONE + */ +void swConfigTagInsertion(PADAPTER_STRUCT Adapter, UINT uPort, UINT bInsert) +{ + uint32_t uReg; + + uReg = KS8695_READ_REG(KS8695_SWITCH_ADVANCED); + if (bInsert) { + uReg |= (1L << (17 + uPort)); + } + else { + uReg &= ~(1L << (17 + uPort)); + } + KS8695_WRITE_REG(KS8695_SWITCH_ADVANCED, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); +} + +/* + * gpioConfigure + * This function is use to configure GPIO pins required for extra LEDs + * as speed indicators. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void gpioConfigure(PADAPTER_STRUCT Adapter) +{ +#if !defined(CONFIG_MACH_CM4002) && !defined(CONFIG_MACH_CM4008) && \ + !defined(CONFIG_MACH_CM41xx) + uint32_t uReg; + uint32_t shift = 0; + +#ifdef KS8695P_MEDIABOX /* note that flag is defined in platform.h for mediabox platform */ + shift = 1; /* shift one bit to right for mediabox, that is from 3-7 - 5-8 */ +#endif + + uReg = KS8695_READ_REG(KS8695_GPIO_MODE); + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + return; +#endif + + case DMA_LAN: + uReg |= (0xf0 << shift); /* GPIO 4-7 for port 1-4 or 5-8 for 1-4 for mediabox, configure them as output */ + break; + + default: + case DMA_WAN: + uReg |= (0x08 << shift); /* GPIO 3 for WAN port, or GPIO 4 in mediabox platform */ + break; + } + KS8695_WRITE_REG(KS8695_GPIO_MODE, uReg); +#endif +} + +/* + * gpioSet + * This function is use to set/reset given GPIO pin corresponding to the port. + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port for the tag to insert + * bSet enable/disable LED + * + * Return(s) + * NONE + */ +void gpioSet(PADAPTER_STRUCT Adapter, UINT uPort, UINT bSet) +{ +#if !defined(CONFIG_MACH_CM4002) && !defined(CONFIG_MACH_CM4008) && \ + !defined(CONFIG_MACH_CM41xx) && !defined(CONFIG_MACH_SE4200) + uint32_t uReg; + uint32_t shift = 0; + +#ifdef KS8695P_MEDIABOX /* note that flag is defined in platform.h for mediabox platform */ + shift = 1; /* if mediabox, shift one bit to right, that is from bit 4-7 shift to bit 5-8 */ +#endif + +#ifdef DEBUG_THIS + DRV_INFO("%s: port %d, %s", __FUNCTION__, uPort, bSet ? "100" : "10"); +#endif + + uReg = KS8695_READ_REG(KS8695_GPIO_DATA); + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + return; +#endif + + case DMA_LAN: + if (bSet) + uReg &= ~(1 << (uPort + 4 + shift)); /* low for LED on */ + else + uReg |= (1 << (uPort + 4 + shift)); /* high for LED off */ + break; + + default: + case DMA_WAN: + if (bSet) + uReg &= ~(0x08 << shift); /* low for LED on */ + else + uReg |= (0x08 << shift); /* high for LED off */ + break; + } + KS8695_WRITE_REG(KS8695_GPIO_DATA, uReg); +#endif +} + +#ifdef CONFIG_ARCH_KS8695P +/* + * configureVID + * This function is use to configure VID for given port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to turn on/off Led + * bFilter enable/disable ingress VLAN filtering + * bDiscard discard Non PVID packets or not + * + * Return(s) + * NONE + */ +void configureVID(PADAPTER_STRUCT Adapter, UINT uPort, UINT bFilter, UINT bDiscard) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C2; + else + off = KS8695_SEP1C2 + uPort * 0x0c; + + uReg = KS8695_READ_REG(off); + if (bFilter) + uReg &= ~KS8695_SEPC2_VLAN_FILTER; + else + uReg |= KS8695_SEPC2_VLAN_FILTER; + if (bDiscard) + uReg &= ~KS8695_SEPC2_DISCARD_NON_PVID; + else + uReg |= KS8695_SEPC2_DISCARD_NON_PVID; + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * backPressureEnable + * This function is use to enable/disable back pressure for given port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to turn on/off Led + * bOn on/off the flow control + * + * Return(s) + * NONE + */ +void backPressureEnable(PADAPTER_STRUCT Adapter, UINT uPort, UINT bOn) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C2; + else + off = KS8695_SEP1C2 + uPort * 0x0c; + + uReg = KS8695_READ_REG(off); + if (bOn) + uReg &= ~KS8695_SEPC2_BACK_PRESSURE_EN; + else + uReg |= KS8695_SEPC2_BACK_PRESSURE_EN; + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * forceFlowControl + * This function is use to force flow control on the port, regardless of AN result + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to turn on/off Led + * bOn on/off the flow control + * + * Return(s) + * NONE + */ +void forceFlowControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bOn) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C2; + else + off = KS8695_SEP1C2 + uPort * 0x0c; + + uReg = KS8695_READ_REG(off); + if (bOn) { + uReg &= ~KS8695_SEPC2_FORCE_FLOW_CTRL; + } else { + uReg |= KS8695_SEPC2_FORCE_FLOW_CTRL; + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * setTxRate + * This function is use to set transmit priority rate control for KS8695P + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to set + * lrate low rate to set + * hrate high rate to set + * + * Return(s) + * NONE + */ +void setTxRate(PADAPTER_STRUCT Adapter, UINT uPort, UINT lrate, UINT hrate) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C2; + else + off = KS8695_SEP1C2 + uPort * 0x0c; + uReg = KS8695_READ_REG(off); + /* clear rate bits first */ + uReg &= ~(KS8695_SEPC2_TX_H_RATECTRL_MASK + KS8695_SEPC2_TX_L_RATECTRL_MASK); + uReg = ((hrate << 12) & KS8695_SEPC2_TX_H_RATECTRL_MASK) + (lrate & KS8695_SEPC2_TX_L_RATECTRL_MASK); + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * setRxRate + * This function is use to set receive priority rate control for KS8695P + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to set + * lrate low rate to set + * hrate high rate to set + * + * Return(s) + * NONE + */ +void setRxRate(PADAPTER_STRUCT Adapter, UINT uPort, UINT lrate, UINT hrate) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C3; + else + off = KS8695_SEP1C3 + uPort * 0x0c; + uReg = KS8695_READ_REG(off); + /* clear rate bits first */ + uReg &= ~(KS8695_SEPC3_RX_H_RATECTRL_MASK + KS8695_SEPC3_RX_L_RATECTRL_MASK); + uReg = ((hrate << 20) & KS8695_SEPC3_RX_H_RATECTRL_MASK) + + ((lrate << 8) & KS8695_SEPC3_RX_L_RATECTRL_MASK); + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enableRxRateFlowControl + * This function is use to enable/disalbe receive priority rate flow control for KS8695P + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to set + * bEnableLowFlow enable low rate flow control + * bEnableHighFlow enable high rate flow control + * + * Return(s) + * NONE + */ +void enableRxRateFlowControl(PADAPTER_STRUCT Adapter, UINT uPort, + UINT bEnableLowFlow, UINT bEnableHighFlow) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C3; + else + off = KS8695_SEP1C3 + uPort * 0x0c; + uReg = KS8695_READ_REG(off); + if (bEnableLowFlow) + uReg |= KS8695_SEPC3_RX_L_RATEFLOW_EN; + else + uReg &= ~KS8695_SEPC3_RX_L_RATEFLOW_EN; + if (bEnableHighFlow) + uReg |= KS8695_SEPC3_RX_H_RATEFLOW_EN; + else + uReg &= ~KS8695_SEPC3_RX_H_RATEFLOW_EN; + + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enableRxRateControl + * This function is use to enable/disalbe receive priority rate control for KS8695P + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to set + * bEnable enable/disable differential priority control + * bEnableLow enable low rate control + * bEnableHigh enable high rate control + * + * Return(s) + * NONE + */ +void enableRxRateControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable, + UINT bEnableLow, UINT bEnableHigh) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C3; + else + off = KS8695_SEP1C3 + uPort * 0x0c; + uReg = KS8695_READ_REG(off); + if (bEnable) + uReg |= KS8695_SEPC3_RX_DIF_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_RX_DIF_RATECTRL_EN; + if (bEnableLow) + uReg |= KS8695_SEPC3_RX_L_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_RX_L_RATECTRL_EN; + if (bEnableHigh) + uReg |= KS8695_SEPC3_RX_H_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_RX_H_RATECTRL_EN; + + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enableTxRateControl + * This function is use to enable/disalbe transmit priority rate control for KS8695P + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort uport to set + * bEnable enable/disable differential priority control + * bEnableLow enable low rate control + * bEnableHigh enable high rate control + * + * Return(s) + * NONE + */ +void enableTxRateControl(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable, + UINT bEnableLow, UINT bEnableHigh) +{ + u32 uReg, off; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) + off = KS8695_SEP5C3; + else + off = KS8695_SEP1C3 + uPort * 0x0c; + uReg = KS8695_READ_REG(off); + if (bEnable) + uReg |= KS8695_SEPC3_TX_DIF_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_TX_DIF_RATECTRL_EN; + if (bEnableLow) + uReg |= KS8695_SEPC3_TX_L_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_TX_L_RATECTRL_EN; + if (bEnableHigh) + uReg |= KS8695_SEPC3_TX_H_RATECTRL_EN; + else + uReg &= ~KS8695_SEPC3_TX_H_RATECTRL_EN; + + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * dumpDynamicMacTable + * This function is use to dump entries in dynamic MAC table + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void dumpDynamicMacTable(PADAPTER_STRUCT Adapter) +{ + u32 reg, v1, v2, timeout = 1000, i = 0; + + printk("Entry Port FID Mac\n"); + do { + reg = KS8695_SEIAC_READ | KS8695_SEIAC_TAB_DYNAMIC | (KS8695_SEIAC_INDEX_MASK & i); + KS8695_WRITE_REG(KS8695_SEIAC, reg); + DelayInMicroseconds(10); + + v1 = KS8695_READ_REG(KS8695_SEIADH2); + if (v1 & 0x10) { /* bit 68 = (68 - 64) */ + /* no valid entries */ + printk("0 entry\n"); + return; + } + v2 = KS8695_READ_REG(KS8695_SEIADH1); + /* if valid entries */ + if (!(v2 & 0x00800000)) { /* bit 55 */ +#if 0 + entries = ((v1 & 0xf) << 6) + (v2 >> 26) + 1; + /* currently just dump first 16 entries (max 1K entries) for demon purpose */ + if (entries > 16) { + printk("%s: more than 16 entries...(v1=0x%08x, v2=0x%08x)\n", + __FUNCTION__, v1, v2); + return; + } +#endif + v1 = KS8695_READ_REG(KS8695_SEIADL); + printk("%04d %04d %4d %02x:%02x:%02x:%02x:%02x:%02x\n", i, + (v2 >> 20) & 0x7, (v2 >> 16) & 0xf, + ((v2 >> 8) & 0xff), (v2 & 0xff), + ((v1 >> 24) & 0xff), ((v1 >> 16) & 0xff), ((v1 >> 8) & 0xff), (v1 & 0xff)); + timeout = 0; + i++; + } + DelayInMicroseconds(1); + } while (timeout-- > 0 || i >= 16); + + if (timeout < 1) + printk("%s: timeout error\n", __FUNCTION__); + if (i >= 16) { + printk("%s: more than 16 entries...v2=0x%08x\n", + __FUNCTION__, v2); + } +} + +/* + * disable8021xFlowControl + * This function is use to disable IEEE 802.1x flow control + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * bTxDisable disable/enable IEEE 802.1x transmit flow control + * bRxDisable disable/enable IEEE 802.1x receive flow control + * + * Return(s) + * NONE + */ +void disable8021xFlowControl(PADAPTER_STRUCT Adapter, UINT bTxDisable, UINT bRxDisable) +{ + u32 uReg, off; + + off = KS8695_SEC1; + uReg = KS8695_READ_REG(off); + if (bTxDisable) { + uReg |= KS8695_SEC1_NO_TX_8021X_FLOW_CTRL; + } else { + uReg &= ~KS8695_SEC1_NO_TX_8021X_FLOW_CTRL; + } + if (bRxDisable) { + uReg |= KS8695_SEC1_NO_RX_8021X_FLOW_CTRL; + } else { + uReg &= ~KS8695_SEC1_NO_RX_8021X_FLOW_CTRL; + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enablePhyLoopback + * This function is enable/disable phy loopback for given port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port to set + * bEnable disable/enable phy loopback + * + * Return(s) + * NONE + */ +void enablePhyLoopback(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable) +{ + u32 uReg, off, shift; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) { + off = KS8695_WAN_POWERMAGR; + } + else { + if (uPort < 2) + off = KS8695_LPPM12; + else + off = KS8695_LPPM34; + } + shift = uPort % 2 ? 0: 1; + uReg = KS8695_READ_REG(off); + if (bEnable) { + uReg |= (KS8695_LPPM_PHY_LOOPBACK << (shift * 16)); + } else { + uReg &= ~(KS8695_LPPM_PHY_LOOPBACK << (shift * 16)); + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enableRemoteLoopback + * This function is enable/disable remote loopback for given port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port to set + * bEnable disable/enable remote loopback + * + * Return(s) + * NONE + */ +void enableRemoteLoopback(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable) +{ + u32 uReg, off, shift; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) { + off = KS8695_WAN_POWERMAGR; + } + else { + if (uPort < 2) + off = KS8695_LPPM12; + else + off = KS8695_LPPM34; + } + shift = uPort % 2 ? 0: 1; + uReg = KS8695_READ_REG(off); + if (bEnable) { + uReg |= (KS8695_LPPM_RMT_LOOPBACK << (shift * 16)); + } else { + uReg &= ~(KS8695_LPPM_RMT_LOOPBACK << (shift * 16)); + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * enablePhyIsolate + * This function is enable/disable phy isolation for given port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port to set + * bEnable disable/enable phy isolation + * + * Return(s) + * NONE + */ +void enablePhyIsolate(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable) +{ + u32 uReg, off, shift; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) { + off = KS8695_WAN_POWERMAGR; + } + else { + if (uPort < 2) + off = KS8695_LPPM12; + else + off = KS8695_LPPM34; + } + shift = uPort % 2 ? 0: 1; + uReg = KS8695_READ_REG(off); + if (bEnable) { + uReg |= (KS8695_LPPM_PHY_ISOLATE << (shift * 16)); + } else { + uReg &= ~(KS8695_LPPM_PHY_ISOLATE << (shift * 16)); + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * forcePhyLink + * This function is enable/disable Link for give port + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * uPort port to set + * bEnable disable/enable phy isolation + * + * Return(s) + * NONE + */ +void forcePhyLink(PADAPTER_STRUCT Adapter, UINT uPort, UINT bEnable) +{ + u32 uReg, off, shift; + + if (uPort > SW_MAX_LAN_PORTS) { + printk("%s: port is out of range\n", __FUNCTION__); + return; + } + if (SW_MAX_LAN_PORTS == uPort) { + off = KS8695_WAN_POWERMAGR; + } + else { + if (uPort < 2) + off = KS8695_LPPM12; + else + off = KS8695_LPPM34; + } + shift = uPort % 2 ? 0: 1; + uReg = KS8695_READ_REG(off); + if (bEnable) { + uReg |= (KS8695_LPPM_FORCE_LINK << (shift * 16)); + } else { + uReg &= ~(KS8695_LPPM_FORCE_LINK << (shift * 16)); + } + KS8695_WRITE_REG(off, uReg); + DelayInMicroseconds(10); +} + +/* + * dumpStaticMacTable + * This function is use to dump entries in static MAC table + * + * Argument(s) + * Adapter pionter to ADAPTER_STRUCT data structure. + * + * Return(s) + * NONE + */ +void dumpStaticMacTable(PADAPTER_STRUCT Adapter) +{ + u32 reg, v1, v2, i = 0; + + printk("Entry Port FID Mac\n"); + for (i = 0; i < 8; i++) { + reg = KS8695_SEIAC_READ | KS8695_SEIAC_TAB_STATIC | (KS8695_SEIAC_INDEX_MASK & i); + KS8695_WRITE_REG(KS8695_SEIAC, reg); + DelayInMicroseconds(10); + + v2 = KS8695_READ_REG(KS8695_SEIADH1); + /* if table entry is valid */ + if (v2 & 0x00200000) { + v1 = KS8695_READ_REG(KS8695_SEIADL); + printk("%04d 0x%02x %4d %02x:%02x:%02x:%02x:%02x:%02x\n", i, + (v2 >> 16) & 0x1f, (v2 >> 24) & 0xf, + ((v2 >> 8) & 0xff), (v2 & 0xff), + ((v1 >> 24) & 0xff), ((v1 >> 16) & 0xff), ((v1 >> 8) & 0xff), (v1 & 0xff)); + } + } +} +#endif + diff --git a/drivers/net/ks8695/ks8695_fxhw.h b/drivers/net/ks8695/ks8695_fxhw.h new file mode 100644 index 00000000..889ec73f --- /dev/null +++ b/drivers/net/ks8695/ks8695_fxhw.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2002, Micrel Kendin Operations + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as lruan@kendin.com + Micrel Kendin Operations + 486 Mercury Dr. + Sunnyvale, CA 94085 + + This driver is for Kendin's KS8695 SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.kendin.com/ks8695/ + +*/ +#ifndef KS8695_FXHW_H +#define KS8695_FXHW_H +#include "ks8695_drv.h" + +#define ASSERT(x) if(!(x)) panic("KS8695: x") +#define DelayInMicroseconds(x) udelay(x) +#define DelayInMilliseconds(x) mdelay(x) + +typedef uint8_t UCHAR, UINT8, BOOLEAN, *PUCHAR; +typedef uint16_t USHORT, UINT16, *PUSHORT; +typedef uint32_t UINT, ULONG, UINT32, *PUINT, *PULONG; + +#define SPEED_UNKNOWN 0 +#define SPEED_10 10 +#define SPEED_100 100 +#define FULL_DUPLEX 1 // default for full duplex +#define HALF_DUPLEX 0 + +#define KS8695_WRITE_REG(reg, value) ((*(volatile uint32_t *)(Adapter->stDMAInfo.nBaseAddr + (reg))) = value) +#define KS8695_READ_REG(reg) (*(volatile uint32_t *)(Adapter->stDMAInfo.nBaseAddr + (reg))) + +#endif /*KS8695_FXHW_H*/ + diff --git a/drivers/net/ks8695/ks8695_ioctrl.h b/drivers/net/ks8695/ks8695_ioctrl.h new file mode 100644 index 00000000..2b5be112 --- /dev/null +++ b/drivers/net/ks8695/ks8695_ioctrl.h @@ -0,0 +1,163 @@ +/* + * ks8695_ictrol.h + * This header file defines the ioctrols supported by the driver. + * + * Copyright (c) 2002-2003, Micrel Semiconductor. All rights reserved. + * + * Modification History + * + * Name Date Ver Brief + * ----------- ----------- ------- -------------------------------------------- + * RLQ 06/03/2003 1.0.0.6 Added new features for KS8695P + * RLQ 08/22/2002 1.0.0.0 First created for sharing among driver, this and web module + */ +#ifndef __KS8695_IOCTRL_H +#define __KS8695_IOCTRL_H + +/* + * local defines + */ +enum { + REG_DMA_DUMP, /* dump all base DMA registers (based on current driver is for) */ + REG_DMA_STATION_DUMP, /* dump all DMA extra station registers */ + REG_UART_DUMP, /* dump all UART related registers */ + REG_INT_DUMP, /* dump all Interrupt related registers */ + REG_TIMER_DUMP, /* dump all Timer related registers */ + REG_GPIO_DUMP, /* dump all GPIO related registers */ + REG_SWITCH_DUMP, /* dump all Switch related registers */ + REG_MISC_DUMP, /* dump all misc registers */ + REG_SNMP_DUMP, /* dump all SNMP registers */ + + DRV_VERSION, /* get driver version, (we need this since proc is removed from driver) */ + + DUMP_PCI_SPACE, /* dump PCI configuration space for KS8695P */ + DUMP_BRIDGE_REG, /* dump bridge related register for KS8695P */ + + MEMORY_DUMP, /* to dump given memory */ + MEMORY_SEARCH, /* to search for given data pattern */ + + REG_WRITE, /* to write IO register */ + + DEBUG_DUMP_TX_PACKET, /* to debug ethernet packet to transmit */ + DEBUG_DUMP_RX_PACKET, /* to debug ethernet packet received */ + + DEBUG_RESET_DESC, /* to reset Rx descriptors */ + DEBUG_STATISTICS, /* debug statistics */ + DEBUG_DESCRIPTORS, /* debug descriptors */ + + DEBUG_LINK_STATUS, /* debug link status */ + + CONFIG_LINK_TYPE, /* configure link media type */ + CONFIG_STATION_EX, /* configure additional station */ + + /* switch configuration for web page */ + CONFIG_SWITCH_GET, /* get switch configuration settings */ + CONFIG_SWITCH_SET, /* set switch configuration settings */ +}; + +/* defined configured SWITCH SUBID */ +enum CONFIG_SWITCH_SUBID { + /* configuration related to basic switch web page */ + CONFIG_SW_SUBID_ON, /* turn on/off switch for LAN */ + CONFIG_SW_SUBID_PORT_VLAN, /* configure port VLAN ID, and Engress mode */ + CONFIG_SW_SUBID_PRIORITY, /* configure port priority */ + + /* configuration related to advanced switch web page */ + CONFIG_SW_SUBID_ADV_LINK_SELECTION, /* configure port link selection */ + CONFIG_SW_SUBID_ADV_CTRL, /* configure switch control register */ + CONFIG_SW_SUBID_ADV_MIRRORING, /* configure switch port mirroring */ + CONFIG_SW_SUBID_ADV_THRESHOLD, /* configure threshold for both 802.1p and broadcast storm protection */ + CONFIG_SW_SUBID_ADV_DSCP, /* configure switch DSCP priority */ + + /* configuration related to Switch internal web page */ + CONFIG_SW_SUBID_INTERNAL_LED, /* configure LED for all */ + CONFIG_SW_SUBID_INTERNAL_MISC, /* configure misc. */ + CONFIG_SW_SUBID_INTERNAL_SPANNINGTREE, /* configure spanning tree */ + + /* configuration phy related features for KS8695P */ + CONFIG_SW_SUBID_PHY_IF, /* configure PHY interface, for KS8695P only */ + CONFIG_SW_SUBID_SEC1, /* configure Switch Engine Control 1 register 0xE804 */ + + /* for KS8695P only */ + CONFIG_SW_SUBID_GENERIC_DUMP, /* generic dump for KS8695), e.g. Dynamic Mac Table, or switch registers */ + CONFIG_SW_SUBID_RATE_CTRL, /* high/low priority rate control */ +}; + +enum GENERIC_DUMP { + GENERIC_DUMP_STATIC, /* dump static Mac table */ + GENERIC_DUMP_DYNAMIC, /* dump dynamic Mac table */ + GENERIC_DUMP_VLAN, /* dump VLAN table */ + GENERIC_DUMP_SWITCH_REGS, /* dump switch registers for KS8695P */ +}; + +/* defined configured SWITCH SUBID */ +enum _DEBUG_PACKET { /* debug packet bit definition */ + DEBUG_PACKET_LEN = 0x00000001, /* debug packet length */ + DEBUG_PACKET_HEADER = 0x00000002, /* debug packet header */ + DEBUG_PACKET_CONTENT = 0x00000004, /* debug packet content */ + DEBUG_PACKET_OVSIZE = 0x00000008, /* dump rx over sized packet content */ + DEBUG_PACKET_UNDERSIZE = 0x00000010, /* prompt rx under sized packet */ +}; + +#define REG_DMA_MAX 8 +#define REG_DMA_STATION_MAX 32 +#define REG_UART_MAX 9 +#define REG_INT_MAX 14 +#define REG_TIMER_MAX 5 +#define REG_GPIO_MAX 3 +#define REG_SWITCH_MAX 21 +#define REG_MISC_MAX 7 +#define REG_SNMP_MAX 138 + +#define DUMP_BUFFER_MAX 1024 + +#define SW_PHY_AUTO 0 /* autosense */ +#define SW_PHY_10BASE_T 1 /* 10Base-T */ +#define SW_PHY_10BASE_T_FD 2 /* 10Base-T Full Duplex */ +#define SW_PHY_100BASE_TX 3 /* 100Base-TX */ +#define SW_PHY_100BASE_TX_FD 4 /* 100Base-TX Full Duplex */ + +/* use __packed in armcc later */ +typedef struct { + uint8_t byId; + uint16_t usLen; + union { + uint32_t uData[0]; + uint16_t usData[0]; + uint8_t byData[0]; + } u; +} IOCTRL, *PIOCTRL; + +typedef struct { + uint8_t byId; + uint16_t usLen; + uint8_t bySubId; + union { + uint32_t uData[0]; + uint16_t usData[0]; + uint8_t byData[0]; + } u; +} IOCTRL_SWITCH, *PIOCTRL_SWITCH; + +enum _LINK_SELECTION { + LINK_SELECTION_FULL_AUTO = 0, /* fully auto nego */ + LINK_SELECTION_FORCED, /* forced mode, no auto nego */ + LINK_SELECTION_PARTIAL_AUTO, /* partial auto nego */ +}; + +/* The proprietary IOCTL code for PHY IO access */ +#define SIOC_KS8695_IOCTRL (SIOCDEVPRIVATE + 15) + +/* Used for mapping mii-tool -> KS8695 register def'ns */ +struct mii_reg { + UINT reg; + UINT shift; +}; + +struct mii_regs { + struct mii_reg config; + struct mii_reg autonego; + struct mii_reg power; +}; + +#endif /*__KS8695_IOCTRL_H*/ diff --git a/drivers/net/ks8695/ks8695_kcompat.h b/drivers/net/ks8695/ks8695_kcompat.h new file mode 100644 index 00000000..e1ec5fd4 --- /dev/null +++ b/drivers/net/ks8695/ks8695_kcompat.h @@ -0,0 +1,316 @@ +/***************************************************************************** + ***************************************************************************** + + Copyright (c) 1999 - 2001, Intel Corporation + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ***************************************************************************** + *****************************************************************************/ + +/* Macros to make drivers compatible with 2.2, 2.4 Linux kernels + * + * In order to make a single network driver work with all 2.2, 2.4 kernels + * these compatibility macros can be used. + * They are backwards compatible implementations of the latest APIs. + * The idea is that these macros will let you use the newest driver with old + * kernels, but can be removed when working with the latest and greatest. + */ + +#ifndef __KS8695_LINUX_KERNEL_COMPAT_H +#define __KS8695_LINUX_KERNEL_COMPAT_H + +#include + +/* a good type to have */ +/* in Linux a long is always the same length as a pointer */ +typedef unsigned long int uintptr_t; + +/***************************************************************************** + ** + ** PCI Bus Changes + ** + *****************************************************************************/ + +/* Accessing the BAR registers from the PCI device structure + * Changed from base_address[bar] to resource[bar].start in 2.3.13 + * The pci_resource_start inline function was introduced in 2.3.43 + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) ) +#define pci_resource_start(dev, bar) \ + (((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_SPACE_IO) ? \ + ((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_IO_MASK) : \ + ((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_MEM_MASK)) +#elif ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define pci_resource_start(dev, bar) \ + (((dev)->resource[(bar)] & PCI_BASE_ADDRESS_SPACE_IO) ? \ + ((dev)->resource[(bar)] & PCI_BASE_ADDRESS_IO_MASK) : \ + ((dev)->resource[(bar)] & PCI_BASE_ADDRESS_MEM_MASK)) +#endif + +/* Starting with 2.3.23 drivers are supposed to call pci_enable_device + * to make sure I/O and memory regions have been mapped and potentially + * bring the device out of a low power state + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,23) ) +#define pci_enable_device(dev) (0) +#endif + +/* Dynamic DMA mapping + * Instead of using virt_to_bus, bus mastering PCI drivers should use the DMA + * mapping API to get bus addresses. This lets some platforms use dynamic + * mapping to use PCI devices that do not support DAC in a 64-bit address space + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,41) ) +#include +#include +#include +#include + +#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) ) || \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) ) ) +typedef unsigned long dma_addr_t; +#endif + +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 + +extern inline void *pci_alloc_consistent (struct pci_dev *dev, + size_t size, + dma_addr_t *dma_handle) { + void *vaddr = kmalloc(size, GFP_KERNEL); + if(vaddr != NULL) { + *dma_handle = virt_to_phys(vaddr); + } + return vaddr; +} + +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ return 1; } + +extern inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ kfree(cpu_addr); return; } + +static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, + size_t size, int direction) +{ return virt_to_phys(ptr); } + +static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, + size_t size, int direction) +{ return; } +/* Ug, this is ks8695 specific */ +#define pci_resource_len(a,b) (128 * 1024) + +static inline int request_mem_region(uintptr_t addr, ...) { return 1; } +static inline int release_mem_region(uintptr_t addr, ...) { return 0; } +#endif + + +/***************************************************************************** + ** + ** Network Device API Changes + ** + *****************************************************************************/ + +/* In 2.3.14 the device structure was renamed to net_device + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14) ) +#define net_device device +#endif + +/* 'Softnet' network stack changes merged in 2.3.43 + * these are 2.2 compatible defines for the new network interface API + * 2.3.47 added some more inline functions for softnet to remove explicit + * bit tests in drivers + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define netif_start_queue(dev) clear_bit (0, &(dev)->tbusy) +#define netif_stop_queue(dev) set_bit (0, &(dev)->tbusy) +#define netif_wake_queue(dev) { clear_bit(0, &(dev)->tbusy); \ + mark_bh(NET_BH); } +#define netif_running(dev) test_bit(0, &(dev)->start) +#define netif_queue_stopped(dev) test_bit(0, &(dev)->tbusy) +#elif ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47) ) +#define netif_running(dev) test_bit(LINK_STATE_START, &(dev)->state) +#define netif_queue_stopped(dev) test_bit(LINK_STATE_XOFF, &(dev)->state) +#endif + +/* Softnet changes also affected how SKBs are handled + * Special calls need to be made now while in an interrupt handler + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) +#define dev_kfree_skb_irq(skb) dev_kfree_skb(skb) +#endif + +/***************************************************************************** + ** + ** General Module / Driver / Kernel API Changes + ** + *****************************************************************************/ + +/* New module_init macro added in 2.3.13 - replaces init_module entry point + * If MODULE is defined, it expands to an init_module definition + * If the driver is staticly linked to the kernel, it creates the proper + * function pointer for the initialization routine to be called + * (no more Space.c) + * module_exit does the same thing for cleanup_module + */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) ) +#define module_init(fn) int init_module (void) { return fn(); } +#define module_exit(fn) void cleanup_module(void) { return fn(); } +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) +#ifndef __KS8695_MAIN__ +#define __NO_VERSION__ +#endif +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47) ) +#define PCI_ANY_ID (~0U) + +struct pci_device_id { + unsigned int vendor, device; + unsigned int subvendor, subdevice; + unsigned int class, classmask; + unsigned long driver_data; +}; + +#define MODULE_DEVICE_TABLE(bus, dev_table) + +struct pci_driver { + char *name; + struct pci_device_id *id_table; + int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); + void (*remove)(struct pci_dev *dev); + void (*suspend)(struct pci_dev *dev); + void (*resume)(struct pci_dev *dev); + /* track devices on Linux 2.2, used by module_init and unregister_driver */ + /* not to be used by the driver directly */ + /* assumes single function device with function #0 to simplify */ + uint32_t pcimap[256]; +}; + +static inline int pci_module_init(struct pci_driver *drv) +{ + struct pci_dev *pdev; + struct pci_device_id *pciid; + uint16_t subvendor, subdevice; + int board_count = 0; + + /* walk the global pci device list looking for matches */ + for (pdev = pci_devices; pdev != NULL; pdev = pdev->next) { + pciid = &drv->id_table[0]; + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subdevice); + + while (pciid->vendor != 0) { + if(((pciid->vendor == pdev->vendor) || + (pciid->vendor == PCI_ANY_ID)) && + + ((pciid->device == pdev->device) || + (pciid->device == PCI_ANY_ID)) && + + ((pciid->subvendor == subvendor) || + (pciid->subvendor == PCI_ANY_ID)) && + + ((pciid->subdevice == subdevice) || + (pciid->subdevice == PCI_ANY_ID))) { + + if(drv->probe(pdev, pciid) == 0) { + board_count++; + + /* keep track of pci devices found */ + set_bit((pdev->devfn >> 3), + &(drv->pcimap[pdev->bus->number])); + } + break; + } + pciid++; + } + } + + return (board_count > 0) ? 0 : -ENODEV; +} + +static inline void pci_unregister_driver(struct pci_driver *drv) +{ + int i, bit; + struct pci_dev *pdev; + + /* search the pci device bitmap and release them all */ + for(i = 0; i < 256; i++) { + /* ffs = find first set bit */ + for(bit = ffs(drv->pcimap[i]); bit > 0; bit = ffs(drv->pcimap[i])) { + bit--; + pdev = pci_find_slot(i, (bit << 3)); + drv->remove(pdev); + clear_bit(bit, &drv->pcimap[i]); + } + } +} +#endif + +/* Taslets */ + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) + +#include +#define tasklet_struct tq_struct + +static inline void tasklet_init(struct tasklet_struct *t, + void (*func)(unsigned long), unsigned long data) +{ + t->next = NULL; + t->sync = 0; + t->routine = (void *)(void *)func; + t->data = (void *)data; +} + +static inline void tasklet_schedule(struct tasklet_struct *t) +{ + queue_task(t, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; +} + +static inline void tasklet_disable(struct tasklet_struct *t) +{ + return; +} + +static inline void tasklet_enable(struct tasklet_struct *t) +{ + return; +} + +#endif + +#endif /* __KS8695_LINUX_KERNEL_COMPAT_H */ + diff --git a/drivers/net/ks8695/ks8695_main.c b/drivers/net/ks8695/ks8695_main.c new file mode 100644 index 00000000..50184a05 --- /dev/null +++ b/drivers/net/ks8695/ks8695_main.c @@ -0,0 +1,4400 @@ +/* + Copyright (c) 2002-2003, Micrel Semiconductor + + Written 2002 by LIQUN RUAN + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as liqun.ruan@micrel.com + Micrel Semiconductor + 1931 Fortune Dr. + San Jose, CA 95131 + + This driver is for Micrel's KS8695/KS8695P SOHO Router Chipset as ethernet driver. + + Support and updates available at + www.micrel.com/ks8695/ not ready yet!!! + +*/ +#define __KS8695_MAIN__ +#include +#include "ks8695_drv.h" +#include "ks8695_ioctrl.h" +#include "ks8695_cache.h" +#include + +#ifdef CONFIG_LEDMAN +#include +#endif + +/* define which external ports do what... */ +#if defined(CONFIG_MACH_CM4008) || defined(CONFIG_MACH_CM41xx) || \ + defined(CONFIG_MACH_LITE300) || defined(CONFIG_MACH_SE4200) +#define LANPORT 0 +#define WANPORT 1 +#define HPNAPORT 2 +#else +#define WANPORT 0 +#define LANPORT 1 +#define HPNAPORT 2 +#endif + +#undef USE_TX_UNAVAIL +#undef USE_RX_UNAVAIL +#undef PACKET_DUMP + +/* process recevied packet in task ReceiveProcessTask().*/ +//RLQ, defined in Makfile +//#define RX_TASK +//#define TX_TASK + +/* process recevied packet in ISR.*/ +#undef HANDLE_RXPACKET_BY_INTERRUPT +#ifdef HANDLE_RXPACKET_BY_INTERRUPT +#undef RX_TASK +#undef TX_TASK +#endif + +#define USE_FIQ + +static int offset = 2; /* shift 2 bytes so that IP header can align to dword boundary */ + +/* update dcache by ourself only if no PCI subsystem is used */ +#define KS8695_MAX_INTLOOP 1 +#define WATCHDOG_TICK 3 + +#ifndef CONFIG_ARCH_KS8695P +#ifdef KS8695X +char ks8695_driver_name[] = "ks8695X SOHO Router 10/100T Ethernet Dirver"; +char ks8695_driver_string[]="Micrel KS8695X Ethernet Network Driver"; +#else +char ks8695_driver_name[] = "ks8695 SOHO Router 10/100T Ethernet Dirver"; +char ks8695_driver_string[]="Micrel KS8695 Ethernet Network Driver"; +#endif /*KS8695X*/ +#else +char ks8695_driver_name[] = "ks8695P SOHO Router 10/100T Ethernet Dirver"; +char ks8695_driver_string[]="Micrel KS8695P Ethernet Network Driver"; +#endif //CONFIG_ARCH_KS8695P +char ks8695_driver_version[] = "1.0.0.20"; +char ks8695_copyright[] = "Copyright (c) 2002-2004 Micrel Semiconductor Corp."; + +PADAPTER_STRUCT ks8695_adapter_list = NULL; + +#if defined(CONFIG_MACH_CM4002) || defined(CONFIG_MACH_CM4008) || \ + defined(CONFIG_MACH_CM41xx) +#define KS8695_MAX_NIC 1 /* Only 1 LAN port used */ +#elif !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) +#define KS8695_MAX_NIC 3 /* 0 for WAN, 1 for LAN and 2 for HPHA */ +#else +#define KS8695_MAX_NIC 2 /* 0 for WAN and 1 for LAN, KS8695X doesn't have HPNA port either */ +#endif //CONFIG_ARCH_KS8695P + +#define STAT_NET(x) (Adapter->net_stats.x) + +static struct pci_dev pci_dev_mimic[KS8695_MAX_NIC]; +static int pci_dev_index = 0; /* max dev probe allowed */ + +#define KS8695_OPTION_INIT { [0 ... KS8695_MAX_NIC - 1] = OPTION_UNSET } + +static int TxDescriptors[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int RxDescriptors[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int Speed[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int Duplex[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int FlowControl[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int RxChecksum[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int TxChecksum[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int TxPBL[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +static int RxPBL[KS8695_MAX_NIC] = KS8695_OPTION_INIT; +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) +static int HPNA = OPTION_UNSET; +#endif +#ifdef __KS8695_CACHE_H +static int PowerSaving = 0; /* default is off */ +static int ICacheLockdown = 0; /* default is off */ +static int RoundRobin = 1; /* default Icache is roundrobin */ +#endif + +/* For mii-tool support */ +static struct mii_regs mii_regs_lan[] = { + { {KS8695_SWITCH_PORT1, }, {KS8695_SWITCH_AUTO0, 16}, {KS8695_LAN12_POWERMAGR, 16} }, + { {KS8695_SWITCH_PORT2, }, {KS8695_SWITCH_AUTO0, 0}, {KS8695_LAN12_POWERMAGR, 0} }, + { {KS8695_SWITCH_PORT3, }, {KS8695_SWITCH_AUTO1, 16}, {KS8695_LAN34_POWERMAGR, 16} }, + { {KS8695_SWITCH_PORT4, }, {KS8695_SWITCH_AUTO1, 0}, {KS8695_LAN34_POWERMAGR, 0} } +}; +static struct mii_regs mii_regs_wan[] = { + { {KS8695_WAN_CONTROL, }, {KS8695_WAN_CONTROL, 16}, {KS8695_WAN_CONTROL, 16} } +}; +static int skipcmd = 0; +static uint16_t ctype = SW_PHY_DEFAULT; + +#ifndef CONFIG_ARCH_KS8695P +#ifdef KS8695X +MODULE_AUTHOR("Micrel Semiconductor, "); +MODULE_DESCRIPTION("Micrel KS8695X SOHO Router Ethernet Network Driver"); +#else +/* for historical reason */ +MODULE_AUTHOR("Micrel Kendin Operations, "); +MODULE_DESCRIPTION("Micrel Kendin KS8695 SOHO Router Ethernet Network Driver"); +#endif +#else +MODULE_AUTHOR("Micrel Semiconductor, "); +MODULE_DESCRIPTION("Micrel KS8695P SOHO Router Ethernet Network Driver"); +#endif +#ifdef ARM_LINUX +MODULE_LICENSE("GPL"); +#endif + +module_param_array(TxDescriptors, int, NULL, 0); +module_param_array(RxDescriptors, int, NULL, 0); +module_param_array(Speed, int, NULL, 0); +module_param_array(Duplex, int, NULL, 0); +module_param_array(FlowControl, int, NULL, 0); +module_param_array(RxChecksum, int, NULL, 0); +module_param_array(TxChecksum, int, NULL, 0); +module_param_array(TxPBL, int, NULL, 0); +module_param_array(RxPBL, int, NULL, 0); +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) +module_param(HPNA, int, 0); +#endif +module_param(PowerSaving, int, 0); +module_param(ICacheLockdown, int, 0); +module_param(RoundRobin, int, 0); + +EXPORT_SYMBOL(ks8695_init_module); +EXPORT_SYMBOL(ks8695_exit_module); +EXPORT_SYMBOL(ks8695_probe); +EXPORT_SYMBOL(ks8695_remove); +EXPORT_SYMBOL(ks8695_open); +EXPORT_SYMBOL(ks8695_close); +EXPORT_SYMBOL(ks8695_xmit_frame); +EXPORT_SYMBOL(ks8695_isr); +EXPORT_SYMBOL(ks8695_isr_link); +EXPORT_SYMBOL(ks8695_set_multi); +EXPORT_SYMBOL(ks8695_change_mtu); +EXPORT_SYMBOL(ks8695_set_mac); +EXPORT_SYMBOL(ks8695_get_stats); +EXPORT_SYMBOL(ks8695_watchdog); +EXPORT_SYMBOL(ks8695_ioctl); + +/* for I-cache lockdown or FIQ purpose */ +EXPORT_SYMBOL(ks8695_isre); + +int ks8695_module_probe(void); +EXPORT_SYMBOL(ks8695_module_probe); + +/********************************************************************* + * Fast timer poll support + *********************************************************************/ + +#if defined(CONFIG_FAST_TIMER) +#define FAST_POLL 1 +#include +static void ks8695_fast_poll(void *arg); +static int ks8695_poll_ready; +#endif + +/********************************************************************* + * Local Function Prototypes + *********************************************************************/ +static void CheckConfigurations(PADAPTER_STRUCT Adapter); +static int SoftwareInit(PADAPTER_STRUCT Adapter); +static int HardwareInit(PADAPTER_STRUCT Adapter); +static int AllocateTxDescriptors(PADAPTER_STRUCT Adapter); +static int AllocateRxDescriptors(PADAPTER_STRUCT Adapter); +static void FreeTxDescriptors(PADAPTER_STRUCT Adapter); +static void FreeRxDescriptors(PADAPTER_STRUCT Adapter); +static void UpdateStatsCounters(PADAPTER_STRUCT Adapter); +#if 0 +static int ProcessTxInterrupts(PADAPTER_STRUCT Adapter); +static int ProcessRxInterrupts(PADAPTER_STRUCT Adapter); +#endif +static void ReceiveBufferFill(uintptr_t data); +static void CleanTxRing(PADAPTER_STRUCT Adapter); +static void CleanRxRing(PADAPTER_STRUCT Adapter); +static void InitTxRing(PADAPTER_STRUCT Adapter); +static void InitRxRing(PADAPTER_STRUCT Adapter); +/*static void ReceiveBufferFillEx(PADAPTER_STRUCT Adapter);*/ +#ifdef __KS8695_CACHE_H +static int ks8695_icache_lock2(void *icache_start, void *icache_end); +#endif + +#ifdef RX_TASK +static void ReceiveProcessTask(uintptr_t data); +#endif +#ifdef TX_TASK +static void TransmitProcessTask(uintptr_t data); +#endif + +/* + * ResetDma + * This function is use to reset DMA in case Tx DMA was sucked due to + * heavy traffic condition. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * 0 if success + * negative value if failed + */ +static __inline void ResetDma(PADAPTER_STRUCT Adapter) +{ + struct net_device *netdev; + /*BOOLEAN bTxStarted, bRxStarted;*/ + UINT uRxReg; + +#ifdef DEBUG_THIS + if (DMA_LAN == DI.usDMAId) { + DRV_INFO("%s: LAN", __FUNCTION__); + } else if (DMA_WAN == DI.usDMAId) { + DRV_INFO("%s: WAN", __FUNCTION__); +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + } else { + DRV_INFO("%s: HPNA", __FUNCTION__); +#endif + } +#endif + + if (!test_bit(KS8695_BOARD_OPEN, &Adapter->flags)) { + DRV_INFO("%s: driver not opened yet", __FUNCTION__); + return; + } + + netdev = Adapter->netdev; + +#ifdef RX_TASK + tasklet_disable(&DI.rx_tasklet); +#endif +#ifdef TX_TASK + tasklet_disable(&DI.tx_tasklet); +#endif + netif_stop_queue(netdev); + + macStopAll(Adapter); + + CleanRxRing(Adapter); + InitRxRing(Adapter); + CleanTxRing(Adapter); + InitTxRing(Adapter); + + ks8695_ChipInit(Adapter, FALSE); + + KS8695_WRITE_REG(KS8695_INT_STATUS, DI.uIntMask); + + /* read RX mode register */ + uRxReg = KS8695_READ_REG(REG_RXCTRL + DI.nOffset); + if (netdev->flags & IFF_PROMISC) { + uRxReg |= DMA_PROMISCUOUS; + } + if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) { + uRxReg |= DMA_MULTICAST; + } + uRxReg |= DMA_BROADCAST; + + /* write RX mode register */ + KS8695_WRITE_REG(REG_RXCTRL + DI.nOffset, uRxReg); + + KS8695_WRITE_REG(REG_RXBASE + DI.nOffset, cpu_to_le32(DI.RxDescDMA)); + KS8695_WRITE_REG(REG_TXBASE + DI.nOffset, cpu_to_le32(DI.TxDescDMA)); + macEnableInterrupt(Adapter, TRUE); + +#ifdef RX_TASK + tasklet_enable( &DI.rx_tasklet ); + if (DI.rx_scheduled) { + tasklet_hi_schedule(&DI.rx_tasklet); + } +#endif +#ifdef TX_TASK + tasklet_enable( &DI.tx_tasklet ); + if (DI.tx_scheduled) { + tasklet_hi_schedule(&DI.tx_tasklet); + } +#endif + netif_start_queue(netdev); + + /*if (bRxStarted)*/ + macStartRx(Adapter, TRUE); + /*if (bTxStarted)*/ + macStartTx(Adapter, TRUE); +} + +/* + * ks8695_dump_packet + * This function is use to dump given packet for debugging. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * data pointer to the beginning of the packet to dump + * len length of the packet + * flag debug flag + * + * Return(s) + * NONE. + */ +#ifndef PING_READY +static __inline void ks8695_dump_packet(PADAPTER_STRUCT Adapter, unsigned char *data, int len, UINT flag) +{ + /* we may need to have locking mechamism to use this function, since Rx call it within INT context + and Tx call it in normal context */ + + if (flag && len >= 18) { + if (flag & DEBUG_PACKET_LEN) { + printk("Pkt Len=%d\n", len); + } + if (flag & DEBUG_PACKET_CONTENT) { + int j = 0, k; + + do { + printk("\n %08x ", (int)(data+j)); + for (k = 0; (k < 16 && len); k++, data++, len--) { + printk("%02x ", *data); + } + j += 16; + } while (len > 0); + printk("\n"); + } + } +} +#endif + +#ifdef PING_READY +static __inline void ks8695_dump_packet(PADAPTER_STRUCT Adapter, unsigned char *data, int len, UINT flag) +{ + /* we may need to have locking mechamism to use this function, since Rx call it within INT context + and Tx call it in normal context */ + + DRV_INFO("%s", __FUNCTION__); + + if (flag && len >= 18) { + if (flag & DEBUG_PACKET_LEN) { + printk("Pkt Len=%d\n", len); + } + if (flag & DEBUG_PACKET_HEADER) { + printk("DA=%02x:%02x:%02x:%02x:%02x:%02x\n", + *data, *(data + 1), *(data + 2), *(data + 3), *(data + 4), *(data + 5)); + printk("SA=%02x:%02x:%02x:%02x:%02x:%02x\n", + *(data + 6), *(data + 7), *(data + 8), *(data + 9), *(data + 10), *(data + 11)); + printk("Type=%04x (%d)\n", ntohs(*(unsigned short *)(data + 12)), ntohs(*(unsigned short *)(data + 12))); + } + if (flag & DEBUG_PACKET_CONTENT) { + int j = 0, k; + + /* skip DA/SA/TYPE, ETH_HLEN is defined in if_ether.h under include/linux dir */ + data += ETH_HLEN; + /*len -= (ETH_HLEN + ETH_CRC_LENGTH);*/ + len -= ETH_HLEN; + do { + printk("\n %04d ", j); + for (k = 0; (k < 16 && len); k++, data++, len--) { + printk("%02x ", *data); + } + j += 16; + } while (len > 0); + /* last dump crc field */ + /*printk("\nCRC=%04x\n", ntohl(*(unsigned int *)data));*/ + } + } +} +#endif + + +/* + * ks8695_relink + * This function is use to setup link in case some dynamic configuration + * is applied via ifconfig! if driver is opened! + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE. + */ +static void ks8695_relink(PADAPTER_STRUCT Adapter) +{ + if (test_bit(KS8695_BOARD_OPEN, &Adapter->flags)) { + /* reset the flag even if it is auto nego is in progress + to make sure we don't miss it!!! */ + if (DMA_LAN != DI.usDMAId) { + swDetectPhyConnection(Adapter, 0); + } + else { + int i; + + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + swDetectPhyConnection(Adapter, i); + } + } + } +} + +/* + * ks8695_report_carrier + * This function is use to report carrier status to net device + * + * Argument(s) + * netdev pointer to net_device structure. + * carrier carrier status (0 off, non zero on) + * + * Return(s) + * NONE. + */ +static void ks8695_report_carrier(struct net_device *netdev, int carrier) +{ +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* if link is on */ + if (carrier) { + netif_carrier_on(netdev); + netif_carrier_ok(netdev); + } + else { + netif_carrier_off(netdev); + } +} + +static void ks8695_tx_timeout(struct net_device *netdev) +{ + printk("%s(%d): ks8695_tx_timeout()\n", __FILE__, __LINE__); +} + +/* + * ks8695_module_probe + * This function is used to simulate pci's probe function. + * + * Argument(s) + * NONE. + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_module_probe(void) +{ +#if 0 + spinlock_t eth_lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; +#endif + int nRet; +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + int nHPHA = 0; +#endif + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + +#ifdef __KS8695_CACHE_H + if (RoundRobin) { + ks8695_icache_change_policy(RoundRobin); + } + if (ICacheLockdown) + ks8695_icache_lock2(ks8695_isr, ks8695_isre); +#endif + + if (pci_dev_index >= KS8695_MAX_NIC) + return -EINVAL; + +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + /* if user enabled HPNA */ + if (HPNA != OPTION_UNSET) { + nHPHA = HPNA ? 1 : 0; + } +#endif + +#ifdef __KS8695_CACHE_H + /* if allow power saving, default no power saving (wait for interrupt) */ + if (PowerSaving) { + ks8695_enable_power_saving(PowerSaving); + } +#endif + + nRet = 0; +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + /* default WAN and LAN, plus HPNA if enabled by the user */ + for (pci_dev_index = 0; pci_dev_index < (2 + nHPHA); pci_dev_index++) { +#else + /* KS8695P and KS8695X has only WAN and LAN */ + for (pci_dev_index = 0; pci_dev_index < KS8695_MAX_NIC; pci_dev_index++) { +#endif + if (0 == pci_dev_index) { + //strcpy(pci_dev_mimic[pci_dev_index].name, "WAN Port"); + pci_dev_mimic[pci_dev_index].irq = 29; + } + else if (1 == pci_dev_index) { + //strcpy(pci_dev_mimic[pci_dev_index].name, "LAN Port"); + pci_dev_mimic[pci_dev_index].irq = 22; + } +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + else { + //strcpy(pci_dev_mimic[pci_dev_index].name, "HPNA Port"); + pci_dev_mimic[pci_dev_index].irq = 14; + } +#endif +#ifdef DEBUG_THIS + DRV_INFO("%s: set ks8695_probe(%d)", __FUNCTION__, pci_dev_index); +#endif +#if 0 + /* We MUST not have interrupts off when calling through this */ + spin_lock_irqsave(ð_lock, flags); +#endif + /* we don't use pci id field, so set it to NULL */ + nRet = ks8695_probe(&pci_dev_mimic[pci_dev_index], NULL); +#if 0 + spin_unlock_irqrestore(ð_lock, flags); +#endif + /* if error happened */ + if (nRet) { + DRV_ERR("%s: ks8695_probe(%d) failed, error code = 0x%08x", __FUNCTION__, pci_dev_index, nRet); + break; + } + } + + return nRet; +} + +/* + * hook_irqs + * This function is used to hook irqs associated to given DMA type + * + * Argument(s) + * netdev pointer to netdev structure. + * req request or free interrupts + * + * Return(s) + * 0 if success + * negative value if failed + */ +static int hook_irqs(struct net_device *netdev, int req) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); +#ifndef FAST_POLL + int i; +#endif + + switch (DI.usDMAId) { + default: +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: +#endif + case DMA_LAN: + break; + + case DMA_WAN: + if (DI.uLinkIntMask & INT_WAN_LINK) { + if (req) { +#ifndef USE_FIQ + if (request_irq(31, ks8695_isr_link, SA_SHIRQ, "WAN eth", netdev)) { +#else + if (request_irq(31, ks8695_isr_link, SA_SHIRQ | SA_INTERRUPT, "WAN eth", netdev)) { +#endif + return -EBUSY; + } + } + else { + free_irq(31, netdev); + } + } + break; + } + +#ifdef FAST_POLL + if (req) + fast_timer_add(ks8695_fast_poll, netdev); + else + fast_timer_remove(ks8695_fast_poll, netdev); +#else + /* each DMA has 6 interrupt bits associated, except WAN which has one extra, INT_WAN_LINK */ + for (i = 0; i < 6; i++) { + if (DI.uIntMask & (1L << (DI.uIntShift + i))) { + if (req) { +#ifndef USE_FIQ + if (request_irq(i + DI.uIntShift, &ks8695_isr, SA_SHIRQ, "LAN eth", netdev)) { +#else + if (request_irq(i + DI.uIntShift, &ks8695_isr, SA_SHIRQ | SA_INTERRUPT, "LAN eth", netdev)) { +#endif + return -EBUSY; + } + } + else { + free_irq(i + DI.uIntShift, netdev); + } + } + } +#endif /* FAST_POLL */ + + return 0; +} + +/* + * Determine MAC addresses for ethernet ports. + */ +#if defined(CONFIG_MACH_CM4002) || defined(CONFIG_MACH_CM4008) || \ + defined(CONFIG_MACH_CM41xx) +#define MAC_OFFSET 0x1c000 +#define MAC_DEFAULT 0x00, 0x13, 0xc6, 0x00, 0x00, 0x00 +#elif defined(CONFIG_MACH_LITE300) || defined(CONFIG_MACH_SE4200) +#define MAC_OFFSET 0x0c000 +#define MAC_DEFAULT 0x00, 0xd0, 0xcf, 0x00, 0x00, 0x00 +#endif + +#ifdef MAC_OFFSET +/* + * Ideally we want to use the MAC addresses stored in flash. + * But we do some sanity checks in case they are not present + * first. + */ +void ks8695_getmac(unsigned char *dst, int index) +{ + unsigned char dm[] = { MAC_DEFAULT }; + unsigned char *src, *mp, *ep; + int i; + + /* Construct a default MAC address just in case */ + dm[ETH_LENGTH_OF_ADDRESS-1] = index; + src = &dm[0]; + + ep = ioremap(0x02000000, 0x20000); + if (ep) { + /* Check if flash MAC is valid */ + mp = ep + MAC_OFFSET + (index * ETH_LENGTH_OF_ADDRESS); + for (i = 0; (i < ETH_LENGTH_OF_ADDRESS); i++) { + if ((mp[i] != 0) && (mp[i] != 0xff)) { + src = mp; + break; + } + } + } + + memcpy(dst, src, ETH_LENGTH_OF_ADDRESS); + + if (ep) + iounmap(ep); +} +#else +void ks8695_getmac(unsigned char *dst, int index) +{ + static char macs[] = { + 0x00, 0x10, 0xa1, 0x00, 0x10, 0x01, + }; + memcpy(dst, macs, ETH_LENGTH_OF_ADDRESS); + macs[ETH_LENGTH_OF_ADDRESS-1]++; +} +#endif + +/* + * ks8695_init_module + * This function is the first routine called when the driver is loaded. + * + * Argument(s) + * NONE. + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_init_module(void) +{ + int nRet; + + /* Print the driver ID string and copyright notice */ + DRV_INFO(" %s, version %s, %s", + ks8695_driver_string, ks8695_driver_version, ks8695_copyright); + +#ifdef DEBUG_THIS + DRV_INFO(" IO Address=0x%x", KS8695_IO_VIRT)); +#endif + + nRet = ks8695_module_probe(); + + return nRet; +} + +module_init(ks8695_init_module); + +/* + * ks8695_exit_module + * This function is called just before the driver is removed from memory. + * + * Argument(s) + * NONE. + * + * Return(s) + * NONE. + */ +void ks8695_exit_module(void) +{ +#ifdef DEBUG_THIS + DRV_INFO("%s: pci_dev_index=%d", __FUNCTION__, pci_dev_index); +#endif + + { + int i; + +#ifdef __KS8695_CACHE_H + if (ICacheLockdown) + ks8695_icache_unlock(); +#endif + for (i = pci_dev_index; i > 0; i--) { + ks8695_remove(&pci_dev_mimic[i - 1]); + } + pci_dev_index = 0; + } +} + +module_exit(ks8695_exit_module); + +/* + * ks8695_probe + * This function initializes an adapter identified by a pci_dev + * structure. Note that KS8695 eval board doesn't have PCI bus at all, + * but the driver uses that since it was derived from a PCI based driver + * originally. + * + * Argument(s) + * pdev pointer to PCI device information struct + * ent pointer to PCI device ID structure (ks8695_pci_table) + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev = NULL; + PADAPTER_STRUCT Adapter; + static int cards_found = 0; + int nRet; + + /* Register a new network interface and allocate private data + structure (ADAPTER_STRUCT) */ + netdev = alloc_etherdev(sizeof(ADAPTER_STRUCT)); + if (NULL == netdev) { + DRV_ERR("alloc_etherdev failed"); + return -ENOMEM; + } + + Adapter = (PADAPTER_STRUCT) netdev_priv(netdev); + /*memset(Adapter, 0, sizeof(ADAPTER_STRUCT));*/ + Adapter->netdev = netdev; + Adapter->pdev = pdev; + + /* chain the ADAPTER_STRUCT into the list */ + if (ks8695_adapter_list) + ks8695_adapter_list->prev = Adapter; + Adapter->next = ks8695_adapter_list; + ks8695_adapter_list = Adapter; + + /* simply tell the network interface we are using this irq, but the driver + use more for each DMA, look for /proc/interrupts for details */ + netdev->irq = pdev->irq; + + Adapter->stDMAInfo.nBaseAddr = KS8695_IO_VIRT; + netdev->mem_start = KS8695_IO_VIRT; + netdev->mem_end = netdev->mem_start + 0xffff; + +/* #ifdef DEBUG_THIS */ + DRV_INFO("VA = 0x%08x, PA=0x%08x", Adapter->stDMAInfo.nBaseAddr, KS8695_IO_BASE); +/* #endif */ + + /* set up function pointers to driver entry points */ + netdev->open = &ks8695_open; + netdev->stop = &ks8695_close; + netdev->hard_start_xmit = &ks8695_xmit_frame; + netdev->get_stats = &ks8695_get_stats; + netdev->set_multicast_list = &ks8695_set_multi; + netdev->set_mac_address = &ks8695_set_mac; + netdev->change_mtu = &ks8695_change_mtu; + netdev->do_ioctl = &ks8695_ioctl; + netdev->tx_timeout = &ks8695_tx_timeout; + netdev->watchdog_timeo = 10*HZ; + if (DI.bTxChecksum) + netdev->features |= NETIF_F_HW_CSUM; + +#ifdef CONFIG_ARCH_KS8695P + Adapter->rev = (KS8695_READ_REG(KS8695_REVISION_ID) >> 0x4) & 0xf; +#else +#ifdef KS8695X + Adapter->rev = (KS8695_READ_REG(KS8695_REVISION_ID) >> 0x4) & 0xf; +#else + Adapter->rev = 0; +#endif /*KS8695X*/ +#endif + + /* the card will tell which driver it will be */ + Adapter->bd_number = cards_found; + + if (WANPORT == cards_found) { + /* for WAN */ + DI.usDMAId = DMA_WAN; + DI.nOffset = DMA_WAN; + DI.uIntMask = INT_WAN_MASK; + DI.uLinkIntMask = INT_WAN_LINK; + +#ifndef USE_RX_UNAVAIL + /* clear Rx buf unavail bit */ + DI.uIntMask &= ~BIT(27); +#endif + +#ifndef USE_TX_UNAVAIL + /* clear Tx buf unavail bit */ + DI.uIntMask &= ~BIT(28); +#endif + /* DMA's stop bit is a little bit different compared with KS9020, so disable them first */ + DI.uIntMask &= ~BIT(26); + DI.uIntMask &= ~BIT(25); + DI.uIntShift = 25; + + /* set default mac address for WAN */ + ks8695_getmac(DI.stMacStation, cards_found); + + } else if (LANPORT == cards_found) { + /* for LAN */ + DI.usDMAId = DMA_LAN; + DI.nOffset = DMA_LAN; + DI.uIntMask = INT_LAN_MASK; + +#ifndef USE_RX_UNAVAIL + /* clear Rx buf unavail bit */ + DI.uIntMask &= ~BIT(14); +#endif + +#ifndef USE_TX_UNAVAIL + /* clear Tx buf unavail bit */ + DI.uIntMask &= ~BIT(15); +#endif + DI.uIntMask &= ~BIT(13); + DI.uIntMask &= ~BIT(12); + DI.uIntShift = 12; + + ks8695_getmac(DI.stMacStation, cards_found); + +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + } else if (HPNAPORT == cards_found) { + /* for HPNA */ + DI.usDMAId = DMA_HPNA; + DI.nOffset = DMA_HPNA; + DI.uIntMask = INT_HPNA_MASK; +#ifdef RX_TASK + /* clear Rx buf unavail bit */ + DI.uIntMask &= ~BIT(20); +#endif +#ifndef USE_TX_UNAVAIL + /* clear Tx buf unavail bit */ + /* if use Tx coalescing, don't disable Tx Complete bit */ + DI.uIntMask &= ~BIT(21); +#else + /* clear Tx Completed bit */ + DI.uIntMask &= ~BIT(23); +#endif + DI.uIntMask &= ~BIT(19); + DI.uIntMask &= ~BIT(18); + + DI.uIntShift = 18; + ks8695_getmac(DI.stMacStation, cards_found); +#endif + } else { + DRV_ERR("%s: card id out of range (%d)", __FUNCTION__, cards_found); + return -ENODEV; + } + + nRet = SoftwareInit(Adapter); + if (nRet) { + DRV_ERR("%s: SoftwareInit failed", __FUNCTION__); + ks8695_remove(pdev); + return nRet; + } + CheckConfigurations(Adapter); + + /* reset spinlock */ + DI.lock = SPIN_LOCK_UNLOCKED; + DI.lock_refill = SPIN_LOCK_UNLOCKED; + + /* finally, we get around to setting up the hardware */ + if (HardwareInit(Adapter) < 0) { + DRV_ERR("%s: HardwareInit failed", __FUNCTION__); + ks8695_remove(pdev); + return -ENODEV; + } + cards_found++; + +#if defined(CONFIG_MACH_LITE300) + /* set LED 0 for link/activities */ + swSetLED(Adapter, FALSE, LED_LINK_ACTIVITY); +#else + /* set LED 0 for speed */ + swSetLED(Adapter, FALSE, LED_SPEED); +#endif + /* set LED 1 for link/activities */ + swSetLED(Adapter, TRUE, LED_LINK_ACTIVITY); + + if ((nRet = register_netdev(netdev))) { + return -EIO; + } + + return 0; +} + +/* + * ks8695_remove + * This function is called by the PCI subsystem to alert the driver + * that it should release a PCI device. It is called to clean up from + * a failure in ks8695_probe. + * + * Argument(s) + * pdev pointer to PCI device information struct + * + * Return(s) + * NONE. + */ +void ks8695_remove(struct pci_dev *pdev) +{ + struct net_device *netdev; + PADAPTER_STRUCT Adapter; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* find the Adapter struct that matches this PCI device */ + for (Adapter = ks8695_adapter_list; Adapter != NULL; Adapter = Adapter->next) { + if (Adapter->pdev == pdev) + break; + } + /* if no match is found */ + if (Adapter == NULL) + return; + +#ifdef DEBUG_THIS + DRV_INFO("%s: match found, bd_num = %d", __FUNCTION__, Adapter->bd_number); +#endif + + netdev = Adapter->netdev; + + if (test_bit(KS8695_BOARD_OPEN, &Adapter->flags)) + ks8695_close(netdev); + + /* remove from the adapter list */ + if (ks8695_adapter_list == Adapter) + ks8695_adapter_list = Adapter->next; + if (Adapter->next != NULL) + Adapter->next->prev = Adapter->prev; + if (Adapter->prev != NULL) + Adapter->prev->next = Adapter->next; + + /* free the net_device _and_ ADAPTER_STRUCT memory */ + unregister_netdev(netdev); + kfree(netdev); +} + +/* + * CheckConfigurations + * This function checks all command line paramters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE. + */ +static void CheckConfigurations(PADAPTER_STRUCT Adapter) +{ + int board = Adapter->bd_number, i; + +#ifdef DEBUG_THIS + DRV_INFO("%s (board number = %d)", __FUNCTION__, board); +#endif + + /* Transmit Descriptor Count */ + if (TxDescriptors[board] == OPTION_UNSET) { + DI.nTxDescTotal = TXDESC_DEFAULT; /* 256 | 128 | 64(d) */ + } else if ((TxDescriptors[board] > TXDESC_MAX) && + (TxDescriptors[board] < TXDESC_MIN)) { + DRV_WARN("Invalid TxDescriptor specified (%d), using default %d", + TxDescriptors[board], TXDESC_DEFAULT); + DI.nTxDescTotal = TXDESC_DEFAULT; + } else { + DRV_INFO("User specified TxDescriptors %d is used", TxDescriptors[board]); + DI.nTxDescTotal = TxDescriptors[board]; + } + /* Tx coalescing, currently can only be used if buffer unavailable bit is set */ + DI.nTransmitCoalescing = (DI.nTxDescTotal >> 3); + + /* Receive Descriptor Count */ + if (RxDescriptors[board] == OPTION_UNSET) { + DI.nRxDescTotal = RXDESC_DEFAULT; /* 256(d) | 128 | 64 */ + } else if ((RxDescriptors[board] > RXDESC_MAX) || + (RxDescriptors[board] < RXDESC_MIN)) { + DRV_WARN("Invalid RxDescriptor specified (%d), using default %d", + RxDescriptors[board], RXDESC_DEFAULT); + } else { + DRV_INFO("User specified RxDescriptors %d is used", RxDescriptors[board]); + DI.nRxDescTotal = RxDescriptors[board]; + } + + /* Receive Checksum Offload Enable */ + if (RxChecksum[board] == OPTION_UNSET) { + DI.bRxChecksum = RXCHECKSUM_DEFAULT; /* enabled */ + } else if ((RxChecksum[board] != OPTION_ENABLED) && (RxChecksum[board] != OPTION_DISABLED)) { + DRV_INFO("Invalid RxChecksum specified (%i), using default of %i", + RxChecksum[board], RXCHECKSUM_DEFAULT); + DI.bRxChecksum = RXCHECKSUM_DEFAULT; + } else { + DRV_INFO("Receive Checksum Offload %s", + RxChecksum[board] == OPTION_ENABLED ? "Enabled" : "Disabled"); + DI.bRxChecksum = RxChecksum[board]; + } + + /* Transmit Checksum Offload Enable configuration */ + if (OPTION_UNSET == TxChecksum[board]) { + DI.bTxChecksum = TXCHECKSUM_DEFAULT; /* disabled */ + } else if ((OPTION_ENABLED != TxChecksum[board]) && (OPTION_DISABLED != TxChecksum[board])) { + DRV_INFO("Invalid TxChecksum specified (%i), using default of %i", + TxChecksum[board], TXCHECKSUM_DEFAULT); + DI.bTxChecksum = TXCHECKSUM_DEFAULT; + } else { + DRV_INFO("Transmit Checksum Offload specified %s", + TxChecksum[board] == OPTION_ENABLED ? "Enabled" : "Disabled"); + DI.bTxChecksum = TxChecksum[board]; + } + + /* Flow Control */ + if (FlowControl[board] == OPTION_UNSET) { + DI.bRxFlowCtrl = FLOWCONTROL_DEFAULT; /* enabled */ + } else if ((OPTION_ENABLED != FlowControl[board]) && (OPTION_DISABLED != FlowControl[board])) { + DRV_INFO("Invalid FlowControl specified (%i), using default %i", + FlowControl[board], FLOWCONTROL_DEFAULT); + DI.bRxFlowCtrl = FLOWCONTROL_DEFAULT; + } else { + DRV_INFO("Flow Control %s", FlowControl[board] == OPTION_ENABLED ? + "Enabled" : "Disabled"); + DI.bRxFlowCtrl = FlowControl[board]; + } + /* currently Tx control flow shares the setting of Rx control flow */ + DI.bTxFlowCtrl = DI.bRxFlowCtrl; + + /* Perform PHY PowerDown Reset instead of soft reset, the Option function can + be overwritten by user later */ + DI.bPowerDownReset = TRUE; + + /* Programmable Burst Length */ + if (OPTION_UNSET == TxPBL[board]) { + DI.byTxPBL = PBL_DEFAULT; /* FIFO size */ + } else if ((0 != TxPBL[board]) && (1 != TxPBL[board]) && (2 != TxPBL[board]) && (4 != TxPBL[board]) && + (8 != TxPBL[board]) && (16 != TxPBL[board]) && (32 != TxPBL[board])) { + DRV_INFO("Invalid TX Programmable Burst Length specified (%i), using default of %i", + TxPBL[board], PBL_DEFAULT); + DI.byTxPBL = PBL_DEFAULT; + } else { + DRV_INFO("Programmable Burst Length specified %d bytes", TxPBL[board]); + DI.byTxPBL = TxPBL[board]; + } + + if (OPTION_UNSET == RxPBL[board]) { + DI.byRxPBL = PBL_DEFAULT; /* FIFO size */ + } else if ((0 != TxPBL[board]) && (1 != RxPBL[board]) && (2 != RxPBL[board]) && (4 != RxPBL[board]) && + (8 != RxPBL[board]) && (16 != RxPBL[board]) && (32 != RxPBL[board])) { + DRV_INFO("Invalid TX Programmable Burst Length specified (%i), using default of %i", + RxPBL[board], PBL_DEFAULT); + DI.byRxPBL = PBL_DEFAULT; + } else { + DRV_INFO("Programmable Burst Length specified %d bytes", RxPBL[board]); + DI.byRxPBL = RxPBL[board]; + } + + /* User speed and/or duplex options */ + if (Duplex[board] == OPTION_UNSET && Speed[board] == OPTION_UNSET) { + DI.usCType[0] = SW_PHY_DEFAULT; + } + else { + switch (Speed[board]) { + case 10: + if (Duplex[board]) + DI.usCType[0] = SW_PHY_10BASE_T_FD; /* 10Base-TX Full Duplex */ + else { + /* don't advertise flow control in half duplex case */ + if (DMA_WAN == DI.usDMAId) { + DI.bRxFlowCtrl = FALSE; + DI.bTxFlowCtrl = FALSE; + } + DI.usCType[0] = SW_PHY_10BASE_T; /* 10Base-T Half Duplex */ + } + break; + + case 100: + default: + if (Duplex[board]) + DI.usCType[0] = SW_PHY_100BASE_TX_FD; /* 100Base-TX Full Duplex */ + else { + /* don't advertise flow control in half duplex case */ + if (DMA_WAN == DI.usDMAId) { + DI.bRxFlowCtrl = FALSE; + DI.bTxFlowCtrl = FALSE; + } + DI.usCType[0] = SW_PHY_100BASE_TX; /* 100Base-TX Half Duplex */ + } + break; + } + } + + if (DMA_LAN == DI.usDMAId) { + /*TEMP, currently assume all other ports share same configuration with + first one, will add more options for LAN ports later */ + for (i = 1; i < SW_MAX_LAN_PORTS; i++) { + DI.usCType[i] = DI.usCType[0]; + } + + /* initialize some variables which do not have user configurable options */ + for (i = 0; i <= SW_MAX_LAN_PORTS; i++) { + DPI[i].byCrossTalkMask = 0x1f; + DPI[i].bySpanningTree = SW_SPANNINGTREE_ALL; + DPI[i].byDisableSpanningTreeLearn = FALSE; + } + + /* set default as direct mode for port 5, so no lookup table is checking */ + DI.bRxDirectMode = FALSE; + DI.bTxRreTagMode = FALSE; + + DI.bPort5FlowCtrl = DI.bRxFlowCtrl; + DI.bPortsFlowCtrl = DI.bRxFlowCtrl; + } +} + +/* + * SoftwareInit + * This function initializes the Adapter private data structure. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure + * + * Return(s) + * 0 if success + * negative value if failed + */ +static int SoftwareInit(PADAPTER_STRUCT Adapter) +{ + struct net_device *netdev = Adapter->netdev; + + /* Initial Receive Buffer Length */ + if ((netdev->mtu + ENET_HEADER_SIZE + ETH_CRC_LENGTH) <= BUFFER_1568) { + DI.uRxBufferLen = BUFFER_1568; /* 0x620 */ + } + else { + DI.uRxBufferLen = BUFFER_2048; /* 0x800 */ + } + + /* please update link status within watchdog routine */ + DI.bLinkChanged[0] = TRUE; + if (DMA_LAN == DI.usDMAId) { /* if LAN driver, 3 more ports */ + DI.bLinkChanged[1] = TRUE; + DI.bLinkChanged[2] = TRUE; + DI.bLinkChanged[3] = TRUE; + } + + return 0; +} + +/* + * HardwareInit + * This function initializes the hardware to a configuration as specified by the + * Adapter structure, including mac I/F, switch engine, IRQ and others. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure + * + * Return(s) + * 0 if success + * negative value if failed + */ +static int HardwareInit(PADAPTER_STRUCT Adapter) +{ +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* note that chip reset should only take once + if three driver instances are used for WAN, LAN and HPNA respectively for KS8695 + For KS8695P only two driver instances are used (WAN and LAN) */ + if (!ks8695_ChipInit(Adapter, TRUE)) { + DRV_ERR("Hardware Initialization Failed"); + return -1; + } + + return 0; +} + +/* + * ks8695_open + * This function is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified when the interface is ready. + * + * Argument(s) + * netdev pointer to net_device struct + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_open(struct net_device *netdev) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* prevent multiple opens on same driver instance */ + if (test_and_set_bit(KS8695_BOARD_OPEN, &Adapter->flags)) { + return -EBUSY; + } +#ifdef FAST_POLL + ks8695_poll_ready = 0; +#endif + + /* stop Tx/Rx and disable interrupt */ + macStopAll(Adapter); + if (DMA_LAN == DI.usDMAId) { + swEnableSwitch(Adapter, FALSE); + } + + if (HardwareInit(Adapter) < 0) { + clear_bit(KS8695_BOARD_OPEN, &Adapter->flags); + return -EBUSY; + } + + /* allocate transmit descriptors */ + if (AllocateTxDescriptors(Adapter) != 0) { + clear_bit(KS8695_BOARD_OPEN, &Adapter->flags); + return -ENOMEM; + } + /* set base address for Tx DMA */ + KS8695_WRITE_REG(REG_TXBASE + DI.nOffset, cpu_to_le32(DI.TxDescDMA)); + macStartTx(Adapter, TRUE); + + /* allocate receive descriptors and buffers */ + if (AllocateRxDescriptors(Adapter) != 0) { + FreeTxDescriptors(Adapter); + clear_bit(KS8695_BOARD_OPEN, &Adapter->flags); + return -ENOMEM; + } + /* set base address for Rx DMA */ + KS8695_WRITE_REG(REG_RXBASE + DI.nOffset, cpu_to_le32(DI.RxDescDMA)); + macStartRx(Adapter, TRUE); + + /* hook the interrupt */ + if (hook_irqs(netdev, TRUE)) { + DRV_ERR("%s: hook_irqs failed", __FUNCTION__); + clear_bit(KS8695_BOARD_OPEN, &Adapter->flags); + FreeTxDescriptors(Adapter); + FreeRxDescriptors(Adapter); + return -EBUSY; + } + + /* fill Rx ring with sk_buffs */ + ReceiveBufferFill((unsigned long)Adapter); + +#ifdef RX_TASK + /* if use task based rx process, initialize it */ + /* Initialize the tasklet again may crash the kernel. */ + if ( DI.rx_tasklet.func == ReceiveProcessTask ) { + tasklet_enable( &DI.rx_tasklet ); + } + else + tasklet_init(&DI.rx_tasklet, ReceiveProcessTask, (unsigned long)Adapter); +#endif +#ifdef TX_TASK + /* if use task based tx process, initialize it */ + /* Initialize the tasklet again may crash the kernel. */ + if ( DI.tx_tasklet.func == TransmitProcessTask ) { + tasklet_enable( &DI.tx_tasklet ); + } + else + tasklet_init(&DI.tx_tasklet, TransmitProcessTask, (unsigned long)Adapter); +#endif + + /* Set the watchdog timer for 2 seconds */ + init_timer(&Adapter->timer_id); + + Adapter->timer_id.function = &ks8695_watchdog; + Adapter->timer_id.data = (unsigned long) netdev; + mod_timer(&Adapter->timer_id, (jiffies + WATCHDOG_TICK * HZ)); + + /* stats accumulated while down are dropped + * this does not clear the running total */ + swResetSNMPInfo(Adapter); + + if (DMA_LAN == DI.usDMAId) { + swEnableSwitch(Adapter, TRUE); + } + macEnableInterrupt(Adapter, TRUE); + + /* clear tbusy bit */ + netif_start_queue(netdev); + +#ifdef FAST_POLL + ks8695_poll_ready++; +#endif + return 0; +} + +/* + * ks8695_close + * This function is called when an interface is de-activated by the network + * module (IFF_DOWN). + * + * Argument(s) + * netdev pointer to net_device struct + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_close(struct net_device *netdev) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + if (!test_bit(KS8695_BOARD_OPEN, &Adapter->flags)) + return 0; + + /* stop all */ + macStopAll(Adapter); + if (DMA_LAN == DI.usDMAId) { + swEnableSwitch(Adapter, FALSE); + } + + netif_stop_queue(netdev); + hook_irqs(netdev, FALSE); + del_timer(&Adapter->timer_id); + +#ifdef RX_TASK + tasklet_disable(&DI.rx_tasklet); + DI.rx_scheduled = FALSE; +#endif +#ifdef TX_TASK + tasklet_disable(&DI.tx_tasklet); + DI.tx_scheduled = FALSE; +#endif + FreeTxDescriptors(Adapter); + FreeRxDescriptors(Adapter); + + clear_bit(KS8695_BOARD_OPEN, &Adapter->flags); + + return 0; +} + +/* + * InitTxRing + * This function is used to initialize Tx descriptor ring. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE + */ +void InitTxRing(PADAPTER_STRUCT Adapter) +{ + int i; + TXDESC *pTxDesc = DI.pTxDescriptors; + UINT32 uPA = DI.TxDescDMA; + + for (i = 0; i < DI.nTxDescTotal - 1; i++, pTxDesc++) { + uPA += sizeof(TXDESC); /* pointer to next Tx Descriptor */ + pTxDesc->TxDMANextPtr = cpu_to_le32(uPA); + } + /* last descriptor should point back to the beginning */ + pTxDesc->TxDMANextPtr = cpu_to_le32(DI.TxDescDMA); + pTxDesc->TxFrameControl |= cpu_to_le32(TFC_TER); +} + + +/* + * KS8695's internal ethernet driver doesn't use PCI bus at all. As a resumt + * call these set of functions instead + */ +static void *consistent_alloc_ex(int gfp, size_t size, dma_addr_t *dma_handle) +{ + struct page *page, *end, *free; + unsigned long order; + void *ret, *virt; + + if (in_interrupt()) + BUG(); + + size = PAGE_ALIGN(size); + order = get_order(size); + + page = alloc_pages(gfp, order); + if (!page) + goto no_page; + + /* + * We could do with a page_to_phys here + */ + virt = page_address(page); + *dma_handle = virt_to_phys(virt); + ret = __ioremap(virt_to_phys(virt), size, 0); + if (!ret) + goto no_remap; + + /* + * free wasted pages. We skip the first page since we know + * that it will have count = 1 and won't require freeing. + * We also mark the pages in use as reserved so that + * remap_page_range works. + */ + page = virt_to_page(virt); + free = page + (size >> PAGE_SHIFT); + end = page + (1 << order); + + for (; page < end; page++) { + if (page >= free) + __free_page(page); + else + SetPageReserved(page); + } + return ret; + +no_remap: + __free_pages(page, order); +no_page: + return NULL; +} + +/* + * free a page as defined by the above mapping. We expressly forbid + * calling this from interrupt context. + */ +static void consistent_free_ex(void *vaddr, size_t size, dma_addr_t handle) +{ + struct page *page, *end; + void *virt; + + if (in_interrupt()) + BUG(); + + virt = phys_to_virt(handle); + + /* + * More messing around with the MM internals. This is + * sick, but then so is remap_page_range(). + */ + size = PAGE_ALIGN(size); + page = virt_to_page(virt); + end = page + (size >> PAGE_SHIFT); + + for (; page < end; page++) + ClearPageReserved(page); + + __iounmap(vaddr); +} + +/* + * AllocateTxDescriptors + * This function is used to allocate Tx descriptors, including allocate memory, + * alignment adjustment, variable initialization and so on. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * 0 if success + * negative value if failed + */ +static int AllocateTxDescriptors(PADAPTER_STRUCT Adapter) +{ + int size; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* allocate data buffers for transmission */ + size = sizeof(struct ks8695_buffer) * DI.nTxDescTotal; + DI.pTxSkb = kmalloc(size, GFP_KERNEL); + if (DI.pTxSkb == NULL) { + return -ENOMEM; + } + memset(DI.pTxSkb, 0, size); + + /* round up to nearest 4K */ + size = KS8695_ROUNDUP(DI.nTxDescTotal * sizeof(TXDESC) + DESC_ALIGNMENT, BUFFER_4K); + DI.pTxDescriptors = consistent_alloc_ex(GFP_KERNEL | GFP_DMA, size, &DI.TxDescDMA); + if (NULL == DI.pTxDescriptors) { + kfree(DI.pTxSkb); + DI.pTxSkb = NULL; + return -ENOMEM; + } + +#ifdef DEBUG_THIS + DRV_INFO("TXDESC> DataBuf=0x%08x, Descriptor=0x%08x, PA=0x%08x", (UINT)DI.pTxSkb, (UINT)DI.pTxDescriptors, (UINT)DI.TxDescDMA); +#endif + memset(DI.pTxDescriptors, 0, size); + + atomic_set(&DI.nTxDescAvail, DI.nTxDescTotal); + DI.nTxDescNextAvail = 0; + DI.nTxDescUsed = 0; + DI.nTransmitCount = 0; + DI.nTxProcessedCount = 0; + DI.bTxNoResource = 0; + + InitTxRing(Adapter); + + return 0; +} + +/* + * InitRxRing + * This function is used to initialize Rx descriptor ring. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE + */ +void InitRxRing(PADAPTER_STRUCT Adapter) +{ + int i; + RXDESC *pRxDesc = DI.pRxDescriptors; + UINT32 uPA = DI.RxDescDMA; + + for (i = 0; i < DI.nRxDescTotal - 1; i++, pRxDesc++) { + uPA += sizeof(RXDESC); /* pointer to next Rx Descriptor */ + pRxDesc->RxDMANextPtr = cpu_to_le32(uPA); + } + /* last descriptor should point back to the beginning */ + pRxDesc->RxDMANextPtr = cpu_to_le32(DI.RxDescDMA); + pRxDesc->RxDMAFragLen &= cpu_to_le32(~RFC_RBS_MASK); +} + +/* + * AllocateRxDescriptors + * This function is used to setup Rx descriptors, including allocate memory, receive SKBs + * alignment adjustment, variable initialization and so on. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * 0 if success + * negative value if failed + */ +static int AllocateRxDescriptors(PADAPTER_STRUCT Adapter) +{ + int size; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + size = sizeof(struct ks8695_buffer) * DI.nRxDescTotal; + DI.pRxSkb = kmalloc(size, GFP_KERNEL); + if (DI.pRxSkb == NULL) { + return -ENOMEM; + } + memset(DI.pRxSkb, 0, size); + + /* Round up to nearest 4K */ + size = KS8695_ROUNDUP(DI.nRxDescTotal * sizeof(RXDESC) + DESC_ALIGNMENT, BUFFER_4K); + DI.pRxDescriptors = consistent_alloc_ex(GFP_KERNEL | GFP_DMA, size, &DI.RxDescDMA); + if (NULL == DI.pRxDescriptors) { + kfree(DI.pRxSkb); + DI.pRxSkb = NULL; + return -ENOMEM; + } + +#ifdef DEBUG_THIS + DRV_INFO("RXDESC> DataBuf=0x%08x, Descriptor=0x%08x, PA=0x%08x", + (UINT)DI.pRxSkb, (UINT)DI.pRxDescriptors, (UINT)DI.RxDescDMA); +#endif + + memset(DI.pRxDescriptors, 0, size); + + DI.nRxDescNextAvail = 0; + atomic_set(&DI.RxDescEmpty, DI.nRxDescTotal); + DI.nRxDescNextToFill = 0; + + InitRxRing(Adapter); + + return 0; +} + +/* + * FreeTxDescriptors + * This function is used to free Tx resources. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE. + */ +static void FreeTxDescriptors(PADAPTER_STRUCT Adapter) +{ + int size; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + CleanTxRing(Adapter); + + kfree(DI.pTxSkb); + DI.pTxSkb = NULL; + + size = KS8695_ROUNDUP(DI.nTxDescTotal * sizeof(TXDESC) + DESC_ALIGNMENT, BUFFER_4K); + consistent_free_ex((void *)DI.pTxDescriptors, size, DI.TxDescDMA); + DI.pTxDescriptors = NULL; + DI.TxDescDMA = 0; +} + +/* + * CleanTxRing + * This function is used to go through Tx descriptor list and clean up any pending resources. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE. + */ +static void CleanTxRing(PADAPTER_STRUCT Adapter) +{ + unsigned long size; + TXDESC *pTxDesc = DI.pTxDescriptors; + int i; + + /* free pending sk_buffs if any */ + for (i = 0; i < DI.nTxDescTotal; i++, pTxDesc++) { + if (NULL != DI.pTxSkb[i].skb) { + dev_kfree_skb(DI.pTxSkb[i].skb); + DI.pTxSkb[i].skb = NULL; + + /* reset corresponding Tx Descriptor structure as well */ + pTxDesc->TxDMAFragAddr = 0; + pTxDesc->TxOwnBit = 0; + pTxDesc->TxFrameControl = 0; + } + } + DI.nTransmitCount = 0; + DI.nTxProcessedCount = 0; + + size = sizeof(struct ks8695_buffer) * DI.nTxDescTotal; + memset(DI.pTxSkb, 0, size); + + size = KS8695_ROUNDUP(DI.nTxDescTotal * sizeof(TXDESC) + DESC_ALIGNMENT, BUFFER_4K); + memset(DI.pTxDescriptors, 0, size); + atomic_set(&DI.nTxDescAvail, DI.nTxDescTotal); + DI.nTxDescNextAvail = 0; + DI.nTxDescUsed = 0; + + /* for safety!!! */ + KS8695_WRITE_REG(REG_TXBASE + DI.nOffset, 0); +} + +/* + * FreeRxDescriptors + * This function is used to free Rx resources. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE. + */ +static void FreeRxDescriptors(PADAPTER_STRUCT Adapter) +{ + int size; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + +#if 0 +#ifdef RX_TASK + tasklet_disable(&DI.rx_tasklet); + DI.rx_scheduled = FALSE; +#endif +#ifdef TX_TASK + tasklet_disable(&DI.tx_tasklet); + DI.tx_scheduled = FALSE; +#endif +#endif + + CleanRxRing(Adapter); + + kfree(DI.pRxSkb); + DI.pRxSkb = NULL; + + size = KS8695_ROUNDUP(DI.nRxDescTotal * sizeof(RXDESC) + DESC_ALIGNMENT, BUFFER_4K); + consistent_free_ex((void *)DI.pRxDescriptors, size, DI.RxDescDMA); + DI.pRxDescriptors = NULL; + DI.RxDescDMA = 0; +} + +/* + * CleanRxRing + * This function is used to go through Rx descriptor list and clean up any pending resources. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE. + */ +static void CleanRxRing(PADAPTER_STRUCT Adapter) +{ + unsigned long size; + RXDESC *pRxDesc = DI.pRxDescriptors; + int i; + + /* Free pending sk_buffs if any */ + for (i = 0; i < DI.nRxDescTotal; i++, pRxDesc++) { + if (DI.pRxSkb[i].skb != NULL) { + dev_kfree_skb(DI.pRxSkb[i].skb); + DI.pRxSkb[i].skb = NULL; + + /* reset corresponding Rx Descriptor structure as well */ + pRxDesc->RxFrameControl &= cpu_to_le32(~(RFC_FRAMECTRL_MASK | DESC_OWN_BIT)); + pRxDesc->RxDMAFragLen = 0; + pRxDesc->RxDMAFragAddr = 0; + } + } + + size = sizeof(struct ks8695_buffer) * DI.nRxDescTotal; + memset(DI.pRxSkb, 0, size); + + size = KS8695_ROUNDUP(DI.nRxDescTotal * sizeof(RXDESC) + DESC_ALIGNMENT, BUFFER_4K); + memset(DI.pRxDescriptors, 0, size); + atomic_set(&DI.RxDescEmpty, DI.nRxDescTotal); + DI.nRxDescNextAvail = 0; + DI.nRxDescNextToFill = 0; + + /* for safety!!! */ + KS8695_WRITE_REG(REG_RXBASE + DI.nOffset, 0); +} + +/* + * ks8695_set_multi + * This function is used to set Multicast and Promiscuous mode. It is + * called whenever the multicast address list or the network interface + * flags are updated. This routine is resposible for configuring the + * hardware for proper multicast, promiscuous mode, and all-multi behavior. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT struct + * + * Return(s) + * NONE. + */ +void ks8695_set_multi(struct net_device *netdev) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + uint32_t uReg; +#if 0 + uint32_t HwLowAddress, HwHighAddress; + uint16_t HashValue, HashReg, HashBit; + struct dev_mc_list *mc_ptr; +#endif + + BOOLEAN bRxStarted; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + bRxStarted = DI.bRxStarted; + if (bRxStarted) + macStartRx(Adapter, FALSE); + + /* read RX mode register in order to set hardware filter mode */ + uReg = KS8695_READ_REG(REG_RXCTRL + DI.nOffset); + uReg |= DMA_UNICAST | DMA_BROADCAST; + uReg &= ~(DMA_PROMISCUOUS | DMA_MULTICAST); + + if (netdev->flags & IFF_PROMISC) { + uReg |= DMA_PROMISCUOUS; + } + if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) { + uReg |= DMA_MULTICAST; + } + + KS8695_WRITE_REG(REG_RXCTRL + DI.nOffset, uReg); + + if (bRxStarted) + macStartRx(Adapter, TRUE); + + ks8695_relink(Adapter); +} + +/* + * ks8695_watchdog + * This function is a timer callback routine for updating statistics infomration. + * + * Argument(s) + * data pointer to net_device struct + * + * Return(s) + * NONE. + */ +void ks8695_watchdog(unsigned long data) +{ + struct net_device *netdev = (struct net_device *)data; + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + int carrier; + + if (DMA_LAN == DI.usDMAId) { + static int nCheck = 0; + + if (nCheck++ > 6) { + int i; + uint8_t bLinkActive[SW_MAX_LAN_PORTS]; + + nCheck = 0; + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + /* keep a track for previous link active state */ + bLinkActive[i] = DI.bLinkActive[i]; + + carrier = swGetPhyStatus(Adapter, i); + /* if current link state is not same as previous state, means link state changed */ + if (bLinkActive[i] != DI.bLinkActive[i]) { + DI.bLinkChanged[i] = TRUE; + ks8695_report_carrier(netdev, carrier); + } + /* note that since LAN doesn't have Interrupt bit for link status change */ + /* we have to check it to make sure if link is lost, restart it!!! */ + if (!DI.bLinkActive[i]) { + swDetectPhyConnection(Adapter, i); + } + } + } + } + else { + if (!DI.bLinkActive[0]) { + carrier = swGetPhyStatus(Adapter, 0); + ks8695_report_carrier(netdev, carrier); + } +#ifndef TX_TASK + /* handling WAN DMA sucked case if any */ + /*if (DMA_WAN == DI.usDMAId) {*/ + { /* all driver ? */ + static int nCount = 0; + + /* if no tx resource is reported */ + if (DI.bTxNoResource) { + nCount++; + /* if happened 5 times (WATCHDOG_TICK seconds * 5), means most likely, the WAN Tx DMA is died, + reset it again */ + if (nCount > 5) { + DI.nResetCount++; + ResetDma(Adapter); + DI.bTxNoResource = FALSE; + /* wake queue will call mark_bh(NET_BH) to resume tx */ + netif_wake_queue(netdev); + nCount = 0; + } + } + } +#endif + } + UpdateStatsCounters(Adapter); + + /* Reset the timer */ + mod_timer(&Adapter->timer_id, jiffies + WATCHDOG_TICK * HZ); +} + +/* + * ks8695_xmit_frame + * This function is used to called by the stack to initiate a transmit. + * The out of resource condition is checked after each successful Tx + * so that the stack can be notified, preventing the driver from + * ever needing to drop a frame. The atomic operations on + * nTxDescAvail are used to syncronize with the transmit + * interrupt processing code without the need for a spinlock. + * + * Argument(s) + * skb buffer with frame data to transmit + * netdev pointer to network interface device structure + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + TXDESC *pTxDesc; + int i, len; + char *data; + unsigned long flags; + struct sk_buff* org_skb = skb; + +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (netdev->name[3] == '0') ? LEDMAN_LAN1_TX : LEDMAN_LAN2_TX); +#endif + + /* Hardware has problem sending out short frames in which the first + * 4 bytes of MAC destination address are replaced with data at + * location 0x28 after sending out ICMP packets. + */ + if ( skb->len <= 48 ) { + skb = dev_alloc_skb( 50 ); + if ( !skb ) { + Adapter->net_stats.tx_aborted_errors++; + return 1; + } + memcpy( skb->data, org_skb->data, org_skb->len ); + memset( &skb->data[ org_skb->len ], 0, 50 - org_skb->len ); + skb->len = 50; + dev_kfree_skb( org_skb ); + } + len = skb->len; + data = skb->data; +#ifdef DEBUG_THIS + DRV_INFO("%s> len=%d", __FUNCTION__, len); +#endif + + + i = DI.nTxDescNextAvail; + pTxDesc = &DI.pTxDescriptors[i]; + + DI.pTxSkb[i].skb = skb; + DI.pTxSkb[i].length = len; + DI.pTxSkb[i].direction = PCI_DMA_TODEVICE; + consistent_sync(data, DI.uRxBufferLen, PCI_DMA_TODEVICE); + DI.pTxSkb[i].dma = virt_to_phys(data); + + /* set DMA buffer address */ + pTxDesc->TxDMAFragAddr = cpu_to_le32(DI.pTxSkb[i].dma); + +#ifdef PACKET_DUMP + ks8695_dump_packet(Adapter, data, len, DI.uDebugDumpTxPkt); +#endif + + +#if 0 + if (DMA_LAN == DI.usDMAId) { + /* may need to set SPN for IGCP for LAN driver, but do it later; */ + } +#endif + + local_irq_save(flags); + /* note that since we have set the last Tx descriptor back to the first to form */ + /* a ring, there is no need to keep ring end flag for performance sake */ + /* clear some bits operation for optimization!!! */ +#ifndef USE_TX_UNAVAIL + pTxDesc->TxFrameControl = cpu_to_le32((TFC_FS | TFC_LS | TFC_IC) | (len & TFC_TBS_MASK)); +#else + if ((DI.nTransmitCount + 1) % DI.nTransmitCoalescing) { + pTxDesc->TxFrameControl = cpu_to_le32((TFC_FS | TFC_LS) | (len & TFC_TBS_MASK)); + } + else { + pTxDesc->TxFrameControl = cpu_to_le32((TFC_FS | TFC_LS | TFC_IC) | (len & TFC_TBS_MASK)); + } +#endif + + /* set own bit */ + pTxDesc->TxOwnBit = cpu_to_le32(DESC_OWN_BIT); + + /* eanble read transfer for the packet!!! */ + KS8695_WRITE_REG(REG_TXSTART + DI.nOffset, 1); + + /*atomic_dec(&DI.nTxDescAvail);*/ + /*__save_flags_cli(flags);*/ + DI.nTxDescAvail.counter--; + /* update pending transimt packet count */ + DI.nTransmitCount++; + local_irq_restore(flags); + if (atomic_read(&DI.nTxDescAvail) <= 1) { +#ifdef DEBUG_THIS + if (DMA_WAN == DI.usDMAId) + DRV_WARN("%s> no WAN tx descriptors available, tx suspended, nTransmitCount=%d", __FUNCTION__, DI.nTransmitCount); + else if (DMA_LAN == DI.usDMAId) + DRV_WARN("%s> no LAN tx descriptors available, tx suspended, nTransmitCount=%d", __FUNCTION__, DI.nTransmitCount); +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + else + DRV_WARN("%s> no HPNA tx descriptors available, tx suspended, nTransmitCount=%d", __FUNCTION__, DI.nTransmitCount); +#endif +#endif + DI.bTxNoResource = TRUE; + netif_stop_queue(netdev); +#ifdef TX_TASK + /* try eanble read transfer again */ + KS8695_WRITE_REG(REG_TXSTART + DI.nOffset, 1); + if (FALSE == DI.tx_scheduled) { + DI.tx_scheduled = TRUE; + tasklet_hi_schedule(&DI.tx_tasklet); + } +#endif + } + + /* adv to next available descriptor */ + DI.nTxDescNextAvail = ++DI.nTxDescNextAvail % DI.nTxDescTotal; + netdev->trans_start = jiffies; + + return 0; +} + +/* + * ks8695_get_stats + * This function is used to get NIC's SNMP staticstics. + * + * Argument(s) + * netdev network interface device structure + * + * Return(s) + * pointer to net_device_stats structure + */ +struct net_device_stats *ks8695_get_stats(struct net_device *netdev) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + +#ifdef DEBUG_THIS + DRV_INFO("ks8695_get_stats"); +#endif + + return &Adapter->net_stats; +} + +/* + * ks8695_change_mtu + * This function is use to change the Maximum Transfer Unit. + * + * Argument(s) + * netdev pointer to net_device structure. + * new_mtu new_mtu new value for maximum frame size + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_change_mtu(struct net_device *netdev, int new_mtu) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + uint32_t old_mtu = DI.uRxBufferLen; + + DRV_INFO("%s", __FUNCTION__); + + if (new_mtu <= DI.uRxBufferLen) { + netdev->mtu = new_mtu; + return 0; + } + + if ((new_mtu < MINIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) || + new_mtu > BUFFER_2048 - ENET_HEADER_SIZE) { + DRV_ERR("%s> Invalid MTU setting", __FUNCTION__); + return -EINVAL; + } + + if (new_mtu <= BUFFER_1568 - ENET_HEADER_SIZE) { + DI.uRxBufferLen = BUFFER_1568; + } else { + DI.uRxBufferLen = BUFFER_2048; + } + + if (old_mtu != DI.uRxBufferLen) { + /* put DEBUG_THIS after verification please */ + DRV_INFO("%s, old=%d, new=%d", __FUNCTION__, old_mtu, DI.uRxBufferLen); + ResetDma(Adapter); + } + + netdev->mtu = new_mtu; + ks8695_relink(Adapter); + + return 0; +} + +/* + * ks8695_set_mac + * This function is use to change Ethernet Address of the NIC. + * + * Argument(s) + * netdev pointer to net_device structure. + * p pointer to sockaddr structure + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_set_mac(struct net_device *netdev, void *p) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + struct sockaddr *addr = (struct sockaddr *)p; + BOOLEAN bRxStarted, bTxStarted; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + bRxStarted = DI.bRxStarted; + bTxStarted = DI.bTxStarted; + if (bRxStarted) + macStartRx(Adapter, FALSE); + if (bTxStarted) + macStartTx(Adapter, FALSE); + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(DI.stMacCurrent, addr->sa_data, netdev->addr_len); + macSetStationAddress(Adapter, DI.stMacCurrent); + + if (bRxStarted) + macStartRx(Adapter, TRUE); + if (bTxStarted) + macStartTx(Adapter, TRUE); + + ks8695_relink(Adapter); + + return 0; +} + +/* + * UpdateStatsCounters + * This function is used to update the board statistics counters. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure + * + * Return(s) + * NONE + */ +static void UpdateStatsCounters(PADAPTER_STRUCT Adapter) +{ + struct net_device_stats *stats; + + stats= &Adapter->net_stats; +} + +/* + * CheckState + * This function is used to handle error conditions if any. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure + * uISR bit values of ISR register + * + * Return(s) + * NONE. + */ +static __inline void CheckState(PADAPTER_STRUCT Adapter, UINT32 uISR) +{ + BOOLEAN bTxStopped = FALSE, bRxStopped = FALSE; + +#ifdef DEBUG_THIS + DRV_INFO("%s", __FUNCTION__); +#endif + + /* clear all bits other than stop */ + uISR &= (DI.uIntMask & INT_DMA_STOP_MASK); + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + if (uISR & INT_HPNA_TX_STOPPED) + bTxStopped = TRUE; + if (uISR & INT_HPNA_RX_STOPPED) + bRxStopped = TRUE; + break; +#endif + + case DMA_LAN: + if (uISR & INT_LAN_TX_STOPPED) + bTxStopped = TRUE; + if (uISR & INT_LAN_RX_STOPPED) + bRxStopped = TRUE; + break; + + default: + case DMA_WAN: + if (uISR & INT_WAN_TX_STOPPED) + bTxStopped = TRUE; + if (uISR & INT_WAN_RX_STOPPED) + bRxStopped = TRUE; + break; + } + + if (bRxStopped) { + /* if Rx started already, then it is a problem! */ + if (DI.bRxStarted) { + DRV_WARN("%s> RX stopped, ISR=0x%08x", __FUNCTION__, uISR); + + macStartRx(Adapter, FALSE); + DelayInMilliseconds(2); + macStartRx(Adapter, TRUE); + } + else { + /* ACK and clear the bit */ + KS8695_WRITE_REG(KS8695_INT_STATUS, uISR); + } + } + if (bTxStopped) { + /* if Tx started already, then it is a problem! */ + if (DI.bTxStarted) { + DRV_WARN("%s> TX stopped, ISR=0x%08x", __FUNCTION__, uISR); + + macStartTx(Adapter, FALSE); + DelayInMilliseconds(2); + macStartTx(Adapter, TRUE); + } + else { + /* ACK and clear the bit */ + KS8695_WRITE_REG(KS8695_INT_STATUS, uISR); + } + } +} + +/* + * CheckLinkState + * This function is used to check link status to see whether link has changed or not. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * uISR ISR register (should be IMSR) to check + * + * Return(s) + * TRUE if link change has detected + * FALSE otherwise + */ +static __inline BOOLEAN CheckLinkState(PADAPTER_STRUCT Adapter, UINT uISR) +{ + BOOLEAN bLinkChanged = FALSE; + int i; + + switch (DI.usDMAId) { +#if !defined(CONFIG_ARCH_KS8695P) && !defined(KS8695X) + case DMA_HPNA: + /* what to do? */ + return FALSE; +#endif + + case DMA_WAN: + if (uISR & INT_WAN_LINK) { + bLinkChanged = TRUE; + DI.bLinkChanged[0] = TRUE; + } + break; + + default: + case DMA_LAN: + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + if (FALSE == DI.bLinkChanged[i]) { + UINT uReg = KS8695_READ_REG(KS8695_SWITCH_AUTO0 + (i >> 1)); + if (0 == (i % 2)) + uReg >>= 16; + if (!(uReg & SW_AUTONEGO_STAT_LINK)) { + bLinkChanged = TRUE; + DI.bLinkChanged[i] = TRUE; + } + } + } + break; + } + + return bLinkChanged; +} + +/* + * ProcessTxInterrupts + * This function is use to process Tx interrupt, reclaim resources after + * transmit completes. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * how many number of Tx packets are not processed yet. + */ +static int __inline ProcessTxInterrupts(PADAPTER_STRUCT Adapter) +{ + int i; + TXDESC *TransmitDescriptor; + unsigned long flags; + +#ifdef DEBUG_THIS + DRV_INFO("%s> )", __FUNCTION__); +#endif + + i = DI.nTxDescUsed; + TransmitDescriptor = &DI.pTxDescriptors[i]; + while (!(le32_to_cpu(TransmitDescriptor->TxOwnBit) & DESC_OWN_BIT) && DI.nTransmitCount > 0) { + /* note that WAN DMA doesn't have statistics counters associated with, + therefore use local variables to track them instead */ + STAT_NET(tx_packets)++; + STAT_NET(tx_bytes) += DI.pTxSkb[i].length; + dev_kfree_skb_irq(DI.pTxSkb[i].skb); + DI.pTxSkb[i].skb = NULL; + + local_irq_save(flags); + DI.nTxDescAvail.counter++; + DI.nTransmitCount--; + local_irq_restore(flags); + + /* clear corresponding fields */ + TransmitDescriptor->TxDMAFragAddr = 0; + + /* clear all related bits, including len field, control bits and port bits */ + TransmitDescriptor->TxFrameControl = 0; + + /* to next Tx descriptor */ + i = (i + 1) % DI.nTxDescTotal; + TransmitDescriptor = &DI.pTxDescriptors[i]; + DI.nTxProcessedCount++; + } + DI.nTxDescUsed = i; + + if (DI.bTxNoResource && netif_queue_stopped(Adapter->netdev) && + (atomic_read(&DI.nTxDescAvail) > ((DI.nTxDescTotal * 3) >> 2))) { /* 3/4 */ + DI.bTxNoResource = FALSE; + netif_wake_queue(Adapter->netdev); +#ifdef DEBUG_THIS + DRV_INFO("%s> Tx process resumed", __FUNCTION__); +#endif + } + + return DI.nTransmitCount; +} + + +/* + * ProcessRxInterrupts + * This function is use to process Rx interrupt, send received data up + * the network stack. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * how many Rx packets are processed. + */ +static int __inline ProcessRxInterrupts(PADAPTER_STRUCT Adapter) +{ + RXDESC *CurrentDescriptor, *pBegin; + int i, nProcessed = 0; + uint32_t Length; + uint32_t uFrameCtrl; + struct sk_buff *skb; + struct sk_buff *copy_skb; + int cng_level = 0; + +#ifdef DEBUG_THIS + DRV_INFO("%s> )", __FUNCTION__); +#endif + +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, LEDMAN_LAN1_RX); + /*(dev->name[3] == '0') ? LEDMAN_LAN1_RX : LEDMAN_LAN2_RX);*/ +#endif + i = DI.nRxDescNextAvail; + pBegin = CurrentDescriptor = &DI.pRxDescriptors[i]; + + while (!((uFrameCtrl = le32_to_cpu(CurrentDescriptor->RxFrameControl)) & DESC_OWN_BIT)) { + skb = DI.pRxSkb[i].skb; + /* it should never goes here */ + if (NULL == skb) + { + if (!(0 == CurrentDescriptor->RxFrameControl && 0 == CurrentDescriptor->RxDMAFragLen + && 0 == CurrentDescriptor->RxDMAFragAddr)) { + DRV_INFO("%s: inconsistency error, rx desc index=%d", __FUNCTION__, i); + } + break; + } + + /* length with CRC bytes included */ + Length = (uFrameCtrl & RFC_FL_MASK); + + /* test both bits to make sure single packet */ + if ((uFrameCtrl & (RFC_LS | RFC_FS)) != (RFC_LS | RFC_FS)) { + DRV_INFO("%s> spanning packet detected (framectrl=0x%08x, rx desc index=%d)", __FUNCTION__, uFrameCtrl, i); + if (uFrameCtrl & RFC_FS) { + /* first segment */ + Length = DI.uRxBufferLen; + DRV_INFO(" first segment, len=%d", Length); + /* compensite offset CRC */ + Length += ETH_CRC_LENGTH; + } + else if (uFrameCtrl & RFC_LS) { + /* last segment */ + if (Length > DI.uRxBufferLen + ETH_CRC_LENGTH) { + Length -= DI.uRxBufferLen; + DRV_INFO(" last segment, len=%d", Length); + } + else { + DRV_WARN("%s> under size packet (len=%d, buffer=%d)", __FUNCTION__, Length, DI.uRxBufferLen); + STAT_NET(rx_errors)++; + goto CLEAN_UP; + } + } + else { + if (0 == uFrameCtrl) { + /* race condition ? */ + DRV_WARN("FragLen=0x%08x, FragAddr=0x%08x, RxNextPtr=0x%08x, RxDescEmpty=%d, pkt dropped", + CurrentDescriptor->RxDMAFragLen, CurrentDescriptor->RxDMAFragAddr, CurrentDescriptor->RxDMANextPtr, atomic_read(&DI.RxDescEmpty)); +#ifdef PACKET_DUMP + ks8695_dump_packet(Adapter, skb->data, DI.uRxBufferLen, DEBUG_PACKET_LEN | DEBUG_PACKET_HEADER | DEBUG_PACKET_CONTENT); +#endif + } + else { + DRV_WARN("%s> error spanning packet, dropped", __FUNCTION__); + } + STAT_NET(rx_errors)++; + goto CLEAN_UP; + } + } + + /* if error happened!!! */ + if (uFrameCtrl & (RFC_ES | RFC_RE)) { + DRV_WARN("%s> error found (framectrl=0x%08x)", __FUNCTION__, uFrameCtrl); + STAT_NET(rx_errors)++; + if (uFrameCtrl & RFC_TL) { + STAT_NET(rx_length_errors)++; + } + if (uFrameCtrl & RFC_CRC) { + STAT_NET(rx_crc_errors)++; + } + if (uFrameCtrl & RFC_RF) { + STAT_NET(rx_length_errors)++; + } + /* if errors other than ES happened!!! */ + if (uFrameCtrl & RFC_RE) { + DRV_WARN("%s> RFC_RE (MII) (framectrl=0x%08x)", __FUNCTION__, uFrameCtrl); + STAT_NET(rx_errors)++; + } + /* RLQ, 11/07/2002, added more check to IP/TCP/UDP checksum errors */ + if (uFrameCtrl | (RFC_IPE | RFC_TCPE | RFC_UDPE)) { + STAT_NET(rx_errors)++; + } + goto CLEAN_UP; + } + +#ifdef MORE_ERROR_TRACKING + /* for debug purpose */ + if (Length > 1518) { + DI.uRx1518plus++; + + /* note that printout affects the performance figure quite lots, so don't display + it when conducting performance test, like Chariot */ + if (DI.uDebugDumpRxPkt & DEBUG_PACKET_OVSIZE) { + DRV_INFO("%s> oversize pkt, size=%d, RxDesc=%d", __FUNCTION__, Length, i); + } + + /* do early drop */ + STAT_NET(rx_errors)++; + goto CLEAN_UP; + } + + /* for debug purpose */ + if (Length < 64) { + DI.uRxUnderSize++; + /* note that printout affects the performance figure quite lots, so don't display + it when conducting performance test, like Chariot */ + if (DI.uDebugDumpRxPkt & DEBUG_PACKET_UNDERSIZE) { + DRV_INFO("%s> under pkt, size=%d, RxDesc=%d", __FUNCTION__, Length, i); + } + /* do early drop */ + STAT_NET(rx_errors)++; + goto CLEAN_UP; + } +#endif /* #ifdef MORE_ERROR_TRACKING */ + + /* + * if we are here, means a valid packet received!!! Get length of the pacekt + */ + + /* offset CRC bytes! */ + Length -= ETH_CRC_LENGTH; + + /* to do something ? */ + consistent_sync(skb->data, DI.uRxBufferLen, PCI_DMA_FROMDEVICE); + +#ifdef PACKET_DUMP + /* build in debug mechanism */ + ks8695_dump_packet(Adapter, skb->data, Length, DI.uDebugDumpRxPkt); +#endif + + /* + * copy recevied data to a new skb buffer in order to make IP header 32 bit alignment. + */ + copy_skb = dev_alloc_skb(Length + offset ); + if ( copy_skb == NULL) + { + STAT_NET(rx_dropped)++; + cng_level = NET_RX_DROP; + goto CLEAN_UP; + } + copy_skb->dev = Adapter->netdev; + skb_reserve(copy_skb, offset); /* offset frame by 2 bytes */ + + /* read pkt_len bytes into new skb buf */ + memcpy ( skb_put(copy_skb, Length), skb->data, Length ); + + /* pass the copied skb with IP header alignment to uplayer */ + skb = copy_skb; + + /* check and set Rx Checksum Offload flag */ + if (DI.bRxChecksum) + /* tell upper edge that the driver handled it already! */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + skb->protocol = eth_type_trans(skb, Adapter->netdev); + cng_level = netif_rx(skb); + nProcessed++; + + /* note that WAN DMA doesn't have statistics counters associated with, + therefore use local variables to track them instead */ + STAT_NET(rx_packets)++; + STAT_NET(rx_bytes) += Length; + if (uFrameCtrl & RFC_MF) + STAT_NET(multicast)++; + Adapter->netdev->last_rx = jiffies; + +CLEAN_UP: + /* + * done with this descriptor, let ks8695 DMA own it again + */ + CurrentDescriptor->RxFrameControl &= cpu_to_le32(~(RFC_FRAMECTRL_MASK)); + if (pBegin != CurrentDescriptor) + CurrentDescriptor->RxFrameControl |= cpu_to_le32(DESC_OWN_BIT); + + /* go to next rx descriptor */ + i = (i + 1) % DI.nRxDescTotal; + CurrentDescriptor = &DI.pRxDescriptors[i]; + if (pBegin == CurrentDescriptor) /* one round already */ + break; + if (cng_level == NET_RX_DROP || cng_level == NET_RX_CN_HIGH) + break; + } /* while (!((uFrameCtrl = le32_to_cpu(CurrentDescriptor->RxFrameControl)) & DESC_OWN_BIT)) { */ + if (nProcessed) + pBegin->RxFrameControl |= cpu_to_le32(DESC_OWN_BIT); + + DI.nRxDescNextAvail = i; + + /* enable Rx engine!!! */ + KS8695_WRITE_REG(REG_RXSTART + DI.nOffset, 1); + + return nProcessed; +} + +#ifdef FAST_POLL +static void ks8695_fast_poll(void *arg) +{ + PADAPTER_STRUCT Adapter = netdev_priv((struct net_device *)arg); + int i, irq; + + if (ks8695_poll_ready) { + for (i = 0; (i < 6); i++) { + irq = DI.uIntShift + i; + if (DI.uIntMask & (1L << irq)) + ks8695_isr(irq, arg); + } + } +} +#endif + +#ifdef HANDLE_RXPACKET_BY_INTERRUPT +/* + * ks8695_isr + * This function is the Interrupt Service Routine. + * + * Argument(s) + * irq interrupt number + * data pointer to net_device structure + * regs pointer to pt_regs structure + * + * Return(s) + * NONE. + */ +irqreturn_t ks8695_isr(int irq, void *data) +{ + PADAPTER_STRUCT Adapter = netdev_priv((struct net_device *)data); + uint32_t uISR, uISR1, uIER; + +#ifdef DEBUG_THIS + DRV_INFO("%s> HANDLE_RXPACKET_BY_INTERRUPT.)", __FUNCTION__); +#endif + + uISR1 = (1L << irq); + uIER = KS8695_READ_REG(KS8695_INT_ENABLE); + + /* disable corresponding interrupt */ + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER & ~uISR1); + + /* ACK */ + KS8695_WRITE_REG(KS8695_INT_STATUS, uISR1); + + uISR = uISR1 >> DI.uIntShift; + + /* handle Receive Interrupt */ + if (uISR & INT_RX_BIT) + ProcessRxInterrupts(Adapter); + + /* handle Transmit Done Interrupt */ +#ifndef USE_TX_UNAVAIL + if (uISR & INT_TX_BIT) { +#else + if (DI.nTransmitCount) { +#endif + ProcessTxInterrupts(Adapter); + } + + /* Restore Previous Interrupt Settings */ + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER ); + + return IRQ_HANDLED; +} + +#endif /* #ifdef HANDLE_RXPACKET_BY_INTERRUPT */ + + +#ifdef RX_TASK +/* + * ks8695_isr + * This function is the Interrupt Service Routine. + * + * Argument(s) + * irq interrupt number + * data pointer to net_device structure + * regs pointer to pt_regs structure + * + * Return(s) + * NONE. + */ +irqreturn_t ks8695_isr(int irq, void *data) +{ + PADAPTER_STRUCT Adapter = netdev_priv((struct net_device *)data); + uint32_t uISR, uISR1, uIER; + +#ifdef PACKET_DUMP + DRV_INFO("%s> RX_TASK ?)", __FUNCTION__); +#endif + + uISR1 = (1L << irq); + uIER = KS8695_READ_REG(KS8695_INT_ENABLE); + + /* disable corresponding interrupt */ + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER & ~uISR1); + + /* ACK */ + KS8695_WRITE_REG(KS8695_INT_STATUS, uISR1); + + uISR = uISR1 >> DI.uIntShift; + + switch (uISR) { + /* handle Receive Interrupt */ + case INT_RX_BIT: + if (FALSE == DI.rx_scheduled) { + DI.rx_scheduled = TRUE; + tasklet_hi_schedule(&DI.rx_tasklet); + } + uISR1 = 0; + break; + + /* handle Transmit Done Interrupt */ + case INT_TX_BIT: +#ifdef USE_TX_UNAVAIL + /* handle Transmit Buffer Unavailable Interrupt */ + case INT_TX_UNAVAIL_BIT: + case (INT_TX_UNAVAIL_BIT | INT_TX_BIT): +#endif +#ifndef TX_TASK + ProcessTxInterrupts(Adapter); +#else + if (FALSE == DI.tx_scheduled) { + DI.tx_scheduled = TRUE; + tasklet_hi_schedule(&DI.tx_tasklet); + } + uISR1 = 0; +#endif + break; + +#ifdef USE_RX_UNAVAIL + /* handle Receive Buffer Unavailable Interrupt */ + case INT_RX_UNAVAIL_BIT: + break; +#endif + } + + /* Restore Previous Interrupt if not a scheduled task */ + if (uISR1) { + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER ); + } + + return IRQ_HANDLED; +} + +#endif /*RX_TASK*/ + +/* + * ks8695_isre + * for I-cache lockdown or FIQ purpose. Make sure this function is after ks8695_isr immediately. + * + * Argument(s) + * NONE. + * + */ +void ks8695_isre(void) +{ + /* just for the end of ks8695_isr routine, unless we find a way to define end of function + within ks8695_isr itself */ +} + +/* + * ks8695_isr_link + * This function is to process WAN link change interrupt as a special case + * + * Argument(s) + * irq interrupt number + * data pointer to net_device structure + * regs pointer to pt_regs structure + * + * Return(s) + * NONE. + */ +irqreturn_t ks8695_isr_link(int irq, void *data) +{ + PADAPTER_STRUCT Adapter = netdev_priv((struct net_device *)data); + UINT uIER; + + spin_lock(&DI.lock); + uIER = KS8695_READ_REG(KS8695_INT_ENABLE) & ~INT_WAN_LINK; + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER); + spin_unlock(&DI.lock); + + DI.nLinkChangeCount++; + DI.bLinkChanged[0] = TRUE; + + /* start auto nego only when link is down */ + if (!swGetWANLinkStatus(Adapter)) { + swPhyReset(Adapter, 0); + swAutoNegoAdvertisement(Adapter, 0); + swDetectPhyConnection(Adapter, 0); + } + + /* ACK */ + KS8695_WRITE_REG(KS8695_INT_STATUS, INT_WAN_LINK); + spin_lock(&DI.lock); + uIER = KS8695_READ_REG(KS8695_INT_ENABLE) | INT_WAN_LINK; + KS8695_WRITE_REG(KS8695_INT_ENABLE, uIER); + spin_unlock(&DI.lock); + + return IRQ_HANDLED; +} + + +/* + * ReceiveBufferFill + * This function is use to replace used receive buffers with new SBBs + * to Rx descriptors. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE. + */ +static void ReceiveBufferFill(uintptr_t data) +{ + PADAPTER_STRUCT Adapter = (PADAPTER_STRUCT) data; + RXDESC *CurrentDescriptor, *pBegin; + struct sk_buff *skb; + unsigned long flags; + int i; + + if (!test_bit(KS8695_BOARD_OPEN, &Adapter->flags)) { + DI.rx_fill_scheduled = FALSE; + /* enable Rx engine!!! */ + KS8695_WRITE_REG(REG_RXSTART + DI.nOffset, 1); + return; + } + + i = DI.nRxDescNextToFill; + pBegin = CurrentDescriptor = &DI.pRxDescriptors[i]; + + //__save_flags_cli(flags); + while (NULL == DI.pRxSkb[i].skb) { + skb = alloc_skb(DI.uRxBufferLen + offset, GFP_ATOMIC | GFP_DMA); + if (NULL == skb) { + /*DRV_WARN("%s> alloc_skb failed, refill rescheduled again", __FUNCTION__);*/ + break; + } + + skb->dev = Adapter->netdev; + DI.pRxSkb[i].length = DI.uRxBufferLen; + DI.pRxSkb[i].direction = PCI_DMA_FROMDEVICE; +#ifndef RX_TASK + consistent_sync(skb->data, DI.uRxBufferLen, PCI_DMA_FROMDEVICE); +#endif + DI.pRxSkb[i].dma = virt_to_phys(skb->data); + + /* to avoid possible race problem, make the change of these variables atomic */ + local_irq_save(flags); + DI.pRxSkb[i].skb = skb; + + /* setup Rx descriptor!!! */ + CurrentDescriptor->RxDMAFragAddr = cpu_to_le32(DI.pRxSkb[i].dma); + CurrentDescriptor->RxDMAFragLen = cpu_to_le32(DI.uRxBufferLen); + CurrentDescriptor->RxFrameControl |= cpu_to_le32(DESC_OWN_BIT); + + DI.RxDescEmpty.counter--; + local_irq_restore(flags); + + i = (i + 1) % DI.nRxDescTotal; + CurrentDescriptor = &DI.pRxDescriptors[i]; + if (pBegin == CurrentDescriptor) /* one round already */ + break; + } + DI.nRxDescNextToFill = i; + //__restore_flags(flags); + + DI.rx_fill_scheduled = FALSE; + + /* enable Rx engine!!! */ + KS8695_WRITE_REG(REG_RXSTART + DI.nOffset, 1); +} + +static UINT mii_bmcr(PADAPTER_STRUCT Adapter, struct mii_regs *regs) +{ + UINT out = 0, reg; + + reg = KS8695_READ_REG(regs->config.reg); + out |= reg & SW_PORT_FULLDUPLEX ? BMCR_FULLDPLX : 0; + out |= reg & SW_PORT_DISABLE_AUTONEG ? 0 : BMCR_ANENABLE; + out |= reg & SW_PORT_100BASE ? BMCR_SPEED100 : 0; + + reg = KS8695_READ_REG(regs->autonego.reg); + out |= reg & (SW_AUTONEGO_RESTART << regs->autonego.shift) ? BMCR_ANRESTART : 0; + + reg = KS8695_READ_REG(regs->power.reg); + out |= reg & (POWER_POWERDOWN << regs->power.shift) ? BMCR_PDOWN : 0; + + reg = KS8695_READ_REG(REG_TXCTRL + DI.nOffset); + out |= reg & DMA_LOOPBACK ? BMCR_LOOPBACK : 0; + + return out; +} + +static UINT mii_bmsr(PADAPTER_STRUCT Adapter, struct mii_regs *regs) +{ + UINT out = 0, reg; + + reg = KS8695_READ_REG(regs->autonego.reg); + out |= reg & (SW_AUTONEGO_STAT_LINK << regs->autonego.shift) ? BMSR_LSTATUS : 0; + out |= reg & (SW_AUTONEGO_COMPLETE << regs->autonego.shift) ? BMSR_ANEGCOMPLETE : 0; + + reg = KS8695_READ_REG(regs->config.reg); + if (reg & SW_PORT_DISABLE_AUTONEG) { + if (reg & SW_PORT_100BASE) { + if (reg & SW_PORT_FULLDUPLEX) + out |= BMSR_100FULL; + else + out |= BMSR_100HALF; + } else { + if (reg & SW_PORT_FULLDUPLEX) + out |= BMSR_10FULL; + else + out |= BMSR_10HALF; + } + } else + out |= BMSR_ANEGCAPABLE | BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL; + + return out; +} + +static UINT mii_advertise(PADAPTER_STRUCT Adapter, struct mii_regs *regs) +{ + UINT out = 0, reg; + + reg = KS8695_READ_REG(regs->autonego.reg); + out |= ADVERTISE_CSMA; /* Only mode supported */ + out |= reg & (SW_AUTONEGO_ADV_10HD << regs->autonego.shift) ? ADVERTISE_10HALF : 0; + out |= reg & (SW_AUTONEGO_ADV_10FD << regs->autonego.shift) ? ADVERTISE_10FULL : 0; + out |= reg & (SW_AUTONEGO_ADV_100HD << regs->autonego.shift) ? ADVERTISE_100HALF : 0; + out |= reg & (SW_AUTONEGO_ADV_100FD << regs->autonego.shift) ? ADVERTISE_100FULL : 0; + out |= reg & (SW_AUTONEGO_PART_10HD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_10FD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_100HD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_100FD << regs->autonego.shift) ? ADVERTISE_LPACK : 0; + + return out; +} + +static UINT mii_lpa(PADAPTER_STRUCT Adapter, struct mii_regs *regs) +{ + UINT out = 0, reg; + + reg = KS8695_READ_REG(regs->autonego.reg); + out |= ADVERTISE_CSMA; /* Only mode supported */ + out |= reg & (SW_AUTONEGO_PART_10HD << regs->autonego.shift) ? ADVERTISE_10HALF : 0; + out |= reg & (SW_AUTONEGO_PART_10FD << regs->autonego.shift) ? ADVERTISE_10FULL : 0; + out |= reg & (SW_AUTONEGO_PART_100HD << regs->autonego.shift) ? ADVERTISE_100HALF : 0; + out |= reg & (SW_AUTONEGO_PART_100FD << regs->autonego.shift) ? ADVERTISE_100FULL : 0; + out |= reg & (SW_AUTONEGO_PART_10HD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_10FD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_100HD << regs->autonego.shift) || + reg & (SW_AUTONEGO_PART_100FD << regs->autonego.shift) ? LPA_LPACK : 0; + + return out; +} + +static int ks8695_ioctl_switch(PADAPTER_STRUCT Adapter, PIOCTRL_SWITCH pIoCtrl); + +/* + * ks8695_ioctl + * This function is the ioctl entry point. It handles some driver specific IO + * functions. + * + * Argument(s) + * netdev pointer to net_device structure. + * ifr pointer to ifreq structure + * cmd io cmd + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + PADAPTER_STRUCT Adapter = netdev_priv(netdev); + PIOCTRL pIoCtrl; + struct mii_ioctl_data *data; + struct mii_regs *regs; + int nRet = -1; + +#ifdef DEBUG_THIS + DRV_INFO("%s> cmd = 0x%x", __FUNCTION__, cmd); +#endif + + pIoCtrl = (PIOCTRL)ifr->ifr_data; + data = (struct mii_ioctl_data *)&ifr->ifr_data; + + switch(cmd) { + /* + * mii-tool commands + */ + case SIOCGMIIPHY: + case SIOCDEVPRIVATE: + /* Get address of MII PHY */ + data->phy_id = 0; + nRet = 0; + break; + + case SIOCGMIIREG: + case SIOCDEVPRIVATE + 1: + /* + * Read MII PHY register + */ + if (!strcmp(netdev->name, "eth0")) { + if (data->phy_id >= SW_MAX_LAN_PORTS || DI.usDMAId != DMA_LAN) + return -EOPNOTSUPP; + regs = &mii_regs_lan[data->phy_id]; + } else if (!strcmp(netdev->name, "eth1")) { + if (data->phy_id != 0 || DI.usDMAId != DMA_WAN) + return -EOPNOTSUPP; + regs = &mii_regs_wan[0]; + } else + return -EOPNOTSUPP; + + data->val_out = 0; + + switch (data->reg_num) + { + case MII_BMCR: + /* Basic mode control register */ + data->val_out = mii_bmcr(Adapter, regs); + break; + + case MII_BMSR: + /* Basic mode status register */ + data->val_out = mii_bmsr(Adapter, regs); + break; + + case MII_ADVERTISE: + /* Advertisement control register */ + data->val_out = mii_advertise(Adapter, regs); + break; + + case MII_LPA: + /* Link partner ability register */ + data->val_out = mii_lpa(Adapter, regs); + break; + } + nRet = 0; + break; + + case SIOCSMIIREG: + case SIOCDEVPRIVATE + 2: + /* + * Write MII PHY register + */ + if (!strcmp(netdev->name, "eth0")) { + if (data->phy_id >= SW_MAX_LAN_PORTS || DI.usDMAId != DMA_LAN) + return -EOPNOTSUPP; + } else if (!strcmp(netdev->name, "eth1")) { + if (data->phy_id != 0 || DI.usDMAId != DMA_WAN) + return -EOPNOTSUPP; + } else + return -EOPNOTSUPP; + + switch (data->reg_num) + { + case MII_BMCR: + if (skipcmd) { + skipcmd = 0; + break; + } else if (data->val_in & BMCR_ANRESTART) { + /* Restart autonegotiation */ + if (DI.byDisableAutoNego[data->phy_id] == LINK_SELECTION_FORCED) { + if ((DI.usCType[data->phy_id] = ctype) == SW_PHY_AUTO) + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_FULL_AUTO; + else + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_PARTIAL_AUTO; + } + } else if (data->val_in & BMCR_RESET) { + /* Reset to defaults */ + if ((DI.usCType[data->phy_id] = SW_PHY_DEFAULT) == SW_PHY_AUTO) + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_FULL_AUTO; + else + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_PARTIAL_AUTO; + } else { + /* Force link media type */ + if (DI.byDisableAutoNego[data->phy_id] == LINK_SELECTION_PARTIAL_AUTO) + ctype = DI.usCType[data->phy_id]; /* Remember advert media */ + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_FORCED; + + if (data->val_in & BMCR_SPEED100) { + if (data->val_in & BMCR_FULLDPLX) + DI.usCType[data->phy_id] = SW_PHY_100BASE_TX_FD; + else + DI.usCType[data->phy_id] = SW_PHY_100BASE_TX; + } else { + if (data->val_in & BMCR_FULLDPLX) + DI.usCType[data->phy_id] = SW_PHY_10BASE_T_FD; + else + DI.usCType[data->phy_id] = SW_PHY_10BASE_T; + } + } + + swConfigureMediaType(Adapter, + data->phy_id, + DI.usCType[data->phy_id] == SW_PHY_100BASE_TX || + DI.usCType[data->phy_id] == SW_PHY_100BASE_TX_FD ? 1 : 0, + DI.usCType[data->phy_id] == SW_PHY_10BASE_T_FD || + DI.usCType[data->phy_id] == SW_PHY_100BASE_TX_FD ? 1 : 0); + break; + + case MII_ADVERTISE: + DI.byDisableAutoNego[data->phy_id] = LINK_SELECTION_PARTIAL_AUTO; + /* + * mii-tool -A tries to disable then re-enable autonego, + * the cmd to disable autonego looks just like the cmd + * to force 10baseT-HD so set skipcmd to ignore it + */ + skipcmd = 1; + + if (data->val_in & ADVERTISE_10HALF) + DI.usCType[data->phy_id] = SW_PHY_10BASE_T; + if (data->val_in & ADVERTISE_10FULL) + DI.usCType[data->phy_id] = SW_PHY_10BASE_T_FD; + if (data->val_in & ADVERTISE_100HALF) + DI.usCType[data->phy_id] = SW_PHY_100BASE_TX; + if (data->val_in & ADVERTISE_100FULL) + DI.usCType[data->phy_id] = SW_PHY_100BASE_TX_FD; + break; + + default: + break; + } + nRet = 0; + break; + + /* + * Debug commands + */ + case SIOC_KS8695_IOCTRL: + if (ifr->ifr_data) { + UINT32 *pReg, i; + + switch (pIoCtrl->byId) + { + case REG_DMA_DUMP: + if (pIoCtrl->usLen >= (4 * (1 + REG_DMA_MAX) + 3)) { /* 1 + 2 + 4 + 8 * 4 */ + pReg = pIoCtrl->u.uData; + /* tell debug application its offset */ + *pReg++ = DI.nOffset; + for (i = REG_TXCTRL; i <= REG_STATION_HIGH ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i + DI.nOffset); + } + nRet = 0; + } + break; + + case REG_DMA_STATION_DUMP: + if (pIoCtrl->usLen >= (4 * REG_DMA_STATION_MAX + 3)) { /* 1 + 2 + 16 * 2 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = REG_MAC0_LOW; i <= REG_MAC15_HIGH ; i += 8) { + *pReg++ = (UINT32)KS8695_READ_REG(i + DI.nOffset); + *pReg++ = (UINT32)KS8695_READ_REG(i + DI.nOffset + 4); + } + nRet = 0; + } + break; + + case REG_UART_DUMP: + if (pIoCtrl->usLen >= (4 * REG_UART_MAX + 3)) { /* 1 + 2 + 9 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_UART_RX_BUFFER; i <= KS8695_UART_STATUS ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + case REG_INT_DUMP: + if (pIoCtrl->usLen >= (4 * REG_INT_MAX + 3)) { /* 1 + 2 + 14 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_INT_CONTL; i <= KS8695_IRQ_PEND_PRIORITY ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + /* Timer receive related */ + case REG_TIMER_DUMP: + if (pIoCtrl->usLen >= (4 * REG_TIMER_MAX + 3)) { /* 1 + 2 + 5 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_TIMER_CTRL; i <= KS8695_TIMER0_PCOUNT ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + /* GPIO receive related */ + case REG_GPIO_DUMP: + if (pIoCtrl->usLen >= (4 * REG_GPIO_MAX + 3)) { /* 1 + 2 + 3 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_GPIO_MODE; i <= KS8695_GPIO_DATA ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + case REG_SWITCH_DUMP: + if (pIoCtrl->usLen >= (4 * REG_SWITCH_MAX + 3)) { /* 1 + 2 + 21 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_SWITCH_CTRL0; i <= KS8695_LAN34_POWERMAGR ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + case REG_MISC_DUMP: + if (pIoCtrl->usLen >= (4 * REG_MISC_MAX + 3)) { /* 1 + 2 + 7 * 4 */ + pReg = pIoCtrl->u.uData; + for (i = KS8695_DEVICE_ID; i <= KS8695_WAN_PHY_STATUS ; i += 4, pReg++) { + *pReg = (UINT32)KS8695_READ_REG(i); + } + nRet = 0; + } + break; + + case REG_SNMP_DUMP: + /* do we need to restrict its read to LAN driver only? May be later! */ + if (pIoCtrl->usLen >= (4 * REG_SNMP_MAX + 3)) { /* 1 + 2 + 138 * 4 */ + /* each port (1-4) takes 32 counters, and last 10 counters for port */ + pReg = pIoCtrl->u.uData; + for (i = 0; i <= REG_SNMP_MAX ; i++, pReg++) { + *pReg = swReadSNMPReg(Adapter, i); + DelayInMicroseconds(10); + } + nRet = 0; + } + break; + + case DRV_VERSION: + if (pIoCtrl->usLen >= 19) { /* 1 + 2 + 16 */ + if (0 == Adapter->rev) + strncpy(pIoCtrl->u.byData, ks8695_driver_version, 15); + else { + if ((strlen(ks8695_driver_version) + 4) <= 15) { + sprintf(pIoCtrl->u.byData, "%s, 95P.PING.01", ks8695_driver_version); + } + else + strncpy(pIoCtrl->u.byData, ks8695_driver_version, 15); + } + nRet = 0; + } + break; + +#ifdef CONFIG_ARCH_KS8695P + case DUMP_PCI_SPACE: + if (pIoCtrl->usLen >= sizeof(IOCTRL)) { /* 1 + 2 + 1 */ + if (Adapter->rev) { + i = 0; + printk("----- PCI conf Space -----\n"); + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_2000)); i += 4; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_2004)); i += 4; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_2008)); i += 4; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_200C)); i += 4; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_2010)); i += 4; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_2014)); i += 4; + i = 0x2c; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_202C)); i += 4; + i = 0x3c; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(KS8695_203C)); i += 4; + nRet = 0; + } + } + break; + + case DUMP_BRIDGE_REG: + if (pIoCtrl->usLen >= sizeof(IOCTRL)) { /* 1 + 2 + 1 + 1 (optional) */ + if (Adapter->rev) { + printk("----- Bridge Conf Registers -----\n"); + i = KS8695_2100; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2104; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + + i = KS8695_2200; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2204; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2208; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_220C; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2210; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2214; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2218; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_221C; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2220; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + i = KS8695_2224; + printk("0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + nRet = 0; + } + } + break; +#endif //CONFIG_ARCH_KS8695P + case MEMORY_DUMP: + /* dump 32 dwords each time */ + if (pIoCtrl->usLen >= (4 * 32 + 3)) { /* 1 + 2 + 1 + 1 (optional) */ + UINT32 *pReg1; + + /* note that the address is in the first dword, when returned will contain data */ + pReg = pIoCtrl->u.uData; + pReg1 = (UINT32 *)(*pReg); + +#ifdef DEBUG_THIS + DRV_INFO("addr=0x%08x, 0x%0x8", pReg1, *pReg1); +#endif + /* if no null pointer */ + if (pReg1 && (0xc0000000 == ((UINT)pReg1 & 0xc0000000))) { + for (i = 0; i <= 32 ; i++, pReg++, pReg1++) { + *pReg = *pReg1; + } + nRet = 0; + } + else { + DRV_INFO("%s> invalid address: 0x%08x", __FUNCTION__, *pReg1); + nRet = -EINVAL; + } + } + break; + + case MEMORY_SEARCH: + /* dump 32 dwords each time */ + if (pIoCtrl->usLen > 3 && pIoCtrl->usLen < 128) { /* 1 + 2 + optional length */ + DRV_INFO("%s> not implemented yet", __FUNCTION__); + nRet = 0; + } + break; + + case REG_WRITE: + /* write control register */ + if (pIoCtrl->usLen >= 7) { /* 1 + 2 + 1 * 4 */ + UINT uReg; + + uReg = pIoCtrl->u.uData[0]; + if (uReg >= 0xffff) { + return -EINVAL; + } + if (pIoCtrl->usLen < 11) { + /* if no parameter is given, display register value instead */ + printk("Reg(0x%04x) = 0x%08x", uReg, KS8695_READ_REG(uReg)); + } + else { + KS8695_WRITE_REG(uReg, pIoCtrl->u.uData[1]); + } + nRet = 0; + } + break; + + case DEBUG_DUMP_TX_PACKET: + /* set dump tx packet flag */ + if (pIoCtrl->usLen >= 7) { /* 1 + 2 + 4 */ + DI.uDebugDumpTxPkt = pIoCtrl->u.uData[0]; +#ifndef PACKET_DUMP + DRV_INFO("%s> DumpTxPkt was disabled", __FUNCTION__); +#endif + nRet = 0; + } + break; + + case DEBUG_DUMP_RX_PACKET: + /* set dump rx packet flag */ + if (pIoCtrl->usLen >= 7) { /* 1 + 2 + 4 */ + DI.uDebugDumpRxPkt = pIoCtrl->u.uData[0]; +#ifndef PACKET_DUMP + DRV_INFO("%s> DumpRxPkt was disabled", __FUNCTION__); +#endif + nRet = 0; + } + break; + + case DEBUG_RESET_DESC: + /* set dump rx packet flag */ + if (pIoCtrl->usLen == 3) { /* 1 + 2 */ + ResetDma(Adapter); + nRet = 0; + } + break; + + case DEBUG_STATISTICS: + /* printout statistical counters */ + if (pIoCtrl->usLen == 3) { /* 1 + 2 */ + printk("------- statistics TX -------\n"); + printk("tx_packets = %12u\n", (UINT)STAT_NET(tx_packets)); + printk("tx_bytes = %12u\n", (UINT)STAT_NET(tx_bytes)); + printk("tx_dropped = %12u\n", (UINT)STAT_NET(tx_dropped)); + printk("tx_errors = %12u\n", (UINT)STAT_NET(tx_errors)); + + printk("------- statistics RX -------\n"); + printk("rx_packets = %12u\n", (UINT)STAT_NET(rx_packets)); + printk("rx_bytes = %12u\n", (UINT)STAT_NET(rx_bytes)); + printk("rx_dropped = %12u\n", (UINT)STAT_NET(rx_dropped)); + printk("rx_errors = %12u\n", (UINT)STAT_NET(rx_errors)); + printk("rx_length_errors= %12u\n", (UINT)STAT_NET(rx_length_errors)); + printk("rx_crc_errors = %12u\n", (UINT)STAT_NET(rx_crc_errors)); + printk("collisions = %12u\n", (UINT)STAT_NET(collisions)); + printk("multicast = %12u\n", (UINT)STAT_NET(multicast)); + printk("rx_missed_errors= %12u\n", (UINT)STAT_NET(rx_missed_errors)); + printk("rx_length_errors= %12u\n", (UINT)STAT_NET(rx_length_errors)); + printk("over size pkts = %12u\n", (UINT)DI.uRx1518plus); + printk("under size pkts = %12u\n", (UINT)DI.uRxUnderSize); + printk("TransmitCount = %12u\n", DI.nTransmitCount); + + printk("------- Misc -------\n"); + printk("DMA reset count = %12d\n", DI.nResetCount); + printk("Link change cnt = %12d\n", DI.nLinkChangeCount); + nRet = 0; + } + break; + + case DEBUG_DESCRIPTORS: + /* printout descriptors info */ + if (pIoCtrl->usLen == 3) { /* 1 + 2 */ + printk("------ TX Descriptors ------\n"); + printk("descriptor VA = 0x%08x\n", (UINT)DI.pTxDescriptors); + printk("total = %10d\n", DI.nTxDescTotal); + printk("available = %10d\n", atomic_read(&DI.nTxDescAvail)); + printk("next available = %10d\n", DI.nTxDescNextAvail); + printk("no resource = %10d\n", DI.bTxNoResource); + printk("------ RX Descriptors ------\n"); + printk("descriptor VA = 0x%08x\n", (UINT)DI.pRxDescriptors); + printk("total = %10d\n", DI.nRxDescTotal); + printk("next to fill = %10d\n", DI.nRxDescNextToFill); + printk("next available = %10d\n", DI.nRxDescNextAvail); + printk("empty = %10d\n", atomic_read(&DI.RxDescEmpty)); + nRet = 0; + } + break; + + case DEBUG_LINK_STATUS: + /* printout link status */ + if (pIoCtrl->usLen >= 3) { /* 1 + 2 */ + int i; + + if (DMA_LAN != DI.usDMAId) { + /* RLQ, 1.0.0.14, modified for UPNP query */ + if (pIoCtrl->usLen == 15) { /* 3 + 3 * 4 */ + UINT32 *pReg; + + /* note that the address is in the first dword, when returned will contain data */ + pReg = pIoCtrl->u.uData; + i = 0; + *pReg++ = DI.bLinkActive[i]; /* link active */ + if (!DI.bLinkActive[i]) { + *pReg++ = 0; /* speed */ + *pReg = 0; /* duplex */ + } + else { + *pReg++ = (SPEED_100 == DI.usLinkSpeed[i]) ? 100000000 : 10000000; + *pReg = DI.bHalfDuplex[i]; + } + } + else { /* for back compatible with ks8695_debug utility */ + i = 0; + if (!DI.bLinkActive[i]) { + printk("Link = Down, Speed=Unknown, Duplex=Unknown\n"); + } + else { + if (SW_PHY_AUTO == DI.usCType[i]) { + printk("Link=Up, Speed=%s, Duplex (read)=%s, Duplex (detected)=%s\n", + SPEED_100 == DI.usLinkSpeed[i] ? "100" : "10", + DI.bHalfDuplex[i] ? "Full Duplex" : "Half Duplex", + DI.bHalfDuplexDetected[i] ? "Full Duplex" : "Half Duplex"); + } + else { + printk("Link=Up, Speed=%s, Duplex=%s\n", + SPEED_100 == DI.usLinkSpeed[i] ? "100" : "10", + DI.bHalfDuplex[i] ? "Full Duplex" : "Half Duplex"); + } + } + } + } + else { + /* RLQ, 1.0.0.14, modified for UPNP query */ + if (pIoCtrl->usLen == 3 + 3 * 4 * SW_MAX_LAN_PORTS) { /* 3 + 3 * 4 * 4 = 51 */ + UINT32 *pReg; + + /* note that the address is in the first dword, when returned will contain data */ + pReg = pIoCtrl->u.uData; + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + *pReg++ = DI.bLinkActive[i]; /* link active */ + if (!DI.bLinkActive[i]) { + *pReg++ = 0; /* speed */ + *pReg++ = 0; /* duplex */ + } + else { + *pReg++ = (SPEED_100 == DI.usLinkSpeed[i]) ? 100000000 : 10000000; + *pReg++ = DI.bHalfDuplex[i]; + } + } + } + else { + for (i = 0; i < SW_MAX_LAN_PORTS; i++) { + if (DI.bLinkActive[i]) { + printk("Port[%d] Speed=%s, Duplex (read)=%s, Duplex (detected)=%s\n", (i + 1), + SPEED_100 == DI.usLinkSpeed[i] ? "100" : "10", + DI.bHalfDuplex[i] ? "Full Duplex" : "Half Duplex", + DI.bHalfDuplexDetected[i] ? "Full Duplex" : "Half Duplex"); + } + else { + printk("Port[%d] Speed = Unknown, Duplex = Unknown\n", (i + 1)); + } + } + } + } + nRet = 0; + } + break; + + case CONFIG_LINK_TYPE: + /* configure link media type (forced mode without auto nego) */ + if (pIoCtrl->usLen == 19) { /* 1 + 2 + 4 * 4*/ + uint32_t uPort; + uint32_t uSpeed; + uint32_t uDuplex; + + pReg = pIoCtrl->u.uData; + if (DMA_LAN != DI.usDMAId) { + uPort = 0; + pReg++; + } else { + uPort = *pReg++; + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + } + DI.byDisableAutoNego[uPort] = *pReg++; + uSpeed = *pReg++; + uDuplex = *pReg; + /*DRV_INFO("%s> port=%d, disable autonego=%d, 100=%d, duplex=%d", __FUNCTION__, uPort, DI.byDisableAutoNego[uPort], uSpeed, uDuplex);*/ + swConfigureMediaType(Adapter, uPort, uSpeed, uDuplex); + nRet = 0; + } + break; + + case CONFIG_STATION_EX: + /* configure link media type (forced mode without auto nego) */ + if (pIoCtrl->usLen == 13) { /* 1 + 2 + 4 + 6 */ + pReg = pIoCtrl->u.uData; + + /* uData[0] = set, byData[4-9] = mac address */ + if (pIoCtrl->u.uData[0]) { + int i; + + i = macGetIndexStationEx(Adapter); + if (i >= 0) { + macSetStationEx(Adapter, &pIoCtrl->u.byData[4], i); + nRet = 0; + } + } + else { + macResetStationEx(Adapter, &pIoCtrl->u.byData[4]); + nRet = 0; + } + } + break; + + case CONFIG_SWITCH_GET: + /* we don't really need it since the OS always boots at super mode */ + /* if that is not the case, then enable following line, and add header file if missing ? */ + /*if (!capable(CAP_NET_ADMIN)) return -EPERM;*/ + /* !!! fall over !!! */ + + case CONFIG_SWITCH_SET: + /* for LAN driver only */ + if (DMA_LAN == DI.usDMAId) { + return ks8695_ioctl_switch(Adapter, (PIOCTRL_SWITCH)ifr->ifr_data); + } + else { + if (CONFIG_SW_SUBID_ADV_LINK_SELECTION == ((PIOCTRL_SWITCH)ifr->ifr_data)->bySubId) { + return ks8695_ioctl_switch(Adapter, (PIOCTRL_SWITCH)ifr->ifr_data); + } + else { + /* filter out the IF supported for WAN */ + return -EPERM; + } + } + break; + + default: + DRV_INFO("%s> unsupported parameters: id=%d, len=%d", __FUNCTION__, pIoCtrl->byId, pIoCtrl->usLen); + return -EOPNOTSUPP; + } + break; + } + + default: + return -EOPNOTSUPP; + } + + return nRet; +} + +/* + * ks8695_ioctl_switch + * This function is used to configure CONFIG_SWITCH_SUBID related functions, for web page based + * configuration or for ks8695_debug tool. + * + * Argument(s) + * Adapter pointer to ADAPTER_STRUCT structure. + * pIoCtrl pointer to IOCTRL_SWITCH structure. + * + * Return(s) + * 0 if success + * negative value if failed + */ +int ks8695_ioctl_switch(PADAPTER_STRUCT Adapter, PIOCTRL_SWITCH pIoCtrl) +{ + int nRet = -1; + uint32_t uPort, uReg; + + switch(pIoCtrl->bySubId) { + case CONFIG_SW_SUBID_ON: + if (pIoCtrl->usLen == 8) { /* 1 + 2 + 1 + 4 */ + if (CONFIG_SWITCH_SET == pIoCtrl->byId) + swEnableSwitch(Adapter, pIoCtrl->u.uData[0]); + else { + /* return current switch status */ + pIoCtrl->u.uData[0] = (KS8695_READ_REG(KS8695_SWITCH_CTRL0) & SW_CTRL0_SWITCH_ENABLE) ? TRUE : FALSE; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_PORT_VLAN: + if (pIoCtrl->usLen == 20) { /* 1 + 2 + 1 + 4 * 4 */ + uPort = pIoCtrl->u.uData[0]; + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uint32_t bInsertion; + + DPI[uPort].usTag = (uint16_t)pIoCtrl->u.uData[1]; + /* note that the driver doesn't use VLAN name, so the web page needs to remember it */ + bInsertion = pIoCtrl->u.uData[2]; + DPI[uPort].byCrossTalkMask = (uint8_t)(pIoCtrl->u.uData[3] & 0x1f); +#ifdef DEBUG_THIS + DRV_INFO("%s> port=%d, VID=%d, EgressMode=%s, crosstalk bit=0x%x", __FUNCTION__, uPort, DPI[uPort].usTag, bInsertion ? "tagged" : "untagged"); +#endif + swConfigurePort(Adapter, uPort); + swConfigTagInsertion(Adapter, uPort, bInsertion); + } + else { + pIoCtrl->u.uData[1] = (uint32_t)DPI[uPort].usTag; + pIoCtrl->u.uData[2] = (KS8695_READ_REG(KS8695_SWITCH_ADVANCED) & (1L << (17 + uPort))) ? TRUE : FALSE; + pIoCtrl->u.uData[3] = (uint32_t)DPI[uPort].byCrossTalkMask; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_PRIORITY: + if (pIoCtrl->usLen == 32) { /* 1 + 2 + 1 + 4 * 7 */ + uPort = pIoCtrl->u.uData[0]; + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uint32_t bRemoval; + + DPI[uPort].byIngressPriorityTOS = (uint8_t)pIoCtrl->u.uData[1]; + DPI[uPort].byIngressPriority802_1P = (uint8_t)pIoCtrl->u.uData[2]; + DPI[uPort].byIngressPriority = (uint8_t)pIoCtrl->u.uData[3]; + DPI[uPort].byEgressPriority = (uint8_t)pIoCtrl->u.uData[4]; + bRemoval = (uint8_t)pIoCtrl->u.uData[5]; + DPI[uPort].byStormProtection = (uint8_t)pIoCtrl->u.uData[6]; +#ifdef DEBUG_THIS + DRV_INFO("%s> port=%d, DSCPEnable=%d, IngressPriority802_1P=%d, IngressPriority=%d," + "EgressPriority=%d, IngressTagRemoval=%d, StormProtection=%d", __FUNCTION__, uPort, + DPI[uPort].byIngressPriorityTOS, DPI[uPort].byIngressPriority802_1P, DPI[uPort].byIngressPriority, + DPI[uPort].byEgressPriority, bRemoval, DPI[uPort].byStormProtection); +#endif + swConfigurePort(Adapter, uPort); + swConfigTagRemoval(Adapter, uPort, bRemoval); + } + else { + pIoCtrl->u.uData[1] = (uint32_t)DPI[uPort].byIngressPriorityTOS; + pIoCtrl->u.uData[2] = (uint32_t)DPI[uPort].byIngressPriority802_1P; + pIoCtrl->u.uData[3] = (uint32_t)DPI[uPort].byIngressPriority; + pIoCtrl->u.uData[4] = (uint32_t)DPI[uPort].byEgressPriority; + pIoCtrl->u.uData[6] = (uint32_t)DPI[uPort].byStormProtection; + uReg = KS8695_READ_REG(KS8695_SWITCH_ADVANCED); + pIoCtrl->u.uData[5] = uReg & (1L << (22 + uPort)) ? TRUE : FALSE; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_ADV_LINK_SELECTION: + if (pIoCtrl->usLen >= 16) { /* 1 + 2 + 1 + 4 * (3 | 4) */ + uPort = pIoCtrl->u.uData[0]; + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + if (DMA_LAN != DI.usDMAId) { + uPort = 0; + } + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uint32_t uDuplex; + + if (pIoCtrl->usLen < 20) { + uDuplex = 0; + } + else { + uDuplex = pIoCtrl->u.uData[3]; + } + /* auto nego or forced mode */ + DI.byDisableAutoNego[uPort] = pIoCtrl->u.uData[1]; + swConfigureMediaType(Adapter, uPort, pIoCtrl->u.uData[2], uDuplex); + } + else { + pIoCtrl->u.uData[1] = DI.usCType[uPort]; + pIoCtrl->u.uData[2] = (uint32_t)DI.byDisableAutoNego[uPort]; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_ADV_CTRL: + if (pIoCtrl->usLen == 24) { /* 1 + 2 + 1 + 4 * 5 */ + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + if (pIoCtrl->u.uData[0]) { + uReg |= SW_CTRL0_FLOWCTRL_FAIR; + } + else { + uReg &= ~SW_CTRL0_FLOWCTRL_FAIR; + } + if (pIoCtrl->u.uData[1]) { + uReg |= SW_CTRL0_LEN_CHECKING; + } + else { + uReg &= ~SW_CTRL0_LEN_CHECKING; + } + if (pIoCtrl->u.uData[2]) { + uReg |= SW_CTRL0_AUTO_FAST_AGING; + } + else { + uReg &= ~SW_CTRL0_AUTO_FAST_AGING; + } + if (pIoCtrl->u.uData[3]) { + uReg |= SW_CTRL0_NO_BCAST_STORM_PROT; + } + else { + uReg &= ~SW_CTRL0_NO_BCAST_STORM_PROT; + } + uReg &= 0xfffffff3; /* clear priority scheme fields, 3:2 */ + uReg |= (pIoCtrl->u.uData[4] & 0x3) << 2; + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = uReg & SW_CTRL0_FLOWCTRL_FAIR ? TRUE : FALSE; + pIoCtrl->u.uData[1] = uReg & SW_CTRL0_LEN_CHECKING ? TRUE : FALSE; + pIoCtrl->u.uData[2] = uReg & SW_CTRL0_AUTO_FAST_AGING ? TRUE : FALSE; + pIoCtrl->u.uData[3] = uReg & SW_CTRL0_NO_BCAST_STORM_PROT ? TRUE : FALSE; + pIoCtrl->u.uData[4] = (uReg >> 2) & 0x3; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_ADV_MIRRORING: + if (pIoCtrl->usLen == 24) { /* 1 + 2 + 1 + 4 * 5 */ + uReg = KS8695_READ_REG(KS8695_SWITCH_ADVANCED); + /* note that the port start from 1 - 5 instead of 0 - 5 used internally in the driver */ + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uReg &= 0xfffe0000; /* currently, WEB page allows only on sniffer */ + /* sniffer port */ + if (pIoCtrl->u.uData[0] > 0 && pIoCtrl->u.uData[0] <= 5) { + uReg |= (1L << (pIoCtrl->u.uData[0] - 1)) << 11; + } + /* Tx mirror port */ + if (pIoCtrl->u.uData[1] > 0 && pIoCtrl->u.uData[1] <= 5) { + uReg |= (1L << (pIoCtrl->u.uData[1] - 1)) << 6; + } + /* Rx mirror port */ + if (pIoCtrl->u.uData[2] > 0 && pIoCtrl->u.uData[2] <= 5) { + uReg |= (1L << (pIoCtrl->u.uData[2] - 1)) << 1; + } + /* sniffer mode, 1 for AND 0 for OR */ + if (pIoCtrl->u.uData[3]) { + uReg |= 0x00010000; /* bit 16 */ + } + /* IGMP trap enable */ + if (pIoCtrl->u.uData[4]) { + uReg |= 0x00000001; /* bit 0 */ + } + KS8695_WRITE_REG(KS8695_SWITCH_ADVANCED, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = (uReg >> 11) & 0x1f; + pIoCtrl->u.uData[1] = (uReg >> 6) & 0x1f; + pIoCtrl->u.uData[2] = (uReg >> 1) & 0x1f; + pIoCtrl->u.uData[3] = (uReg & 0x00010000) ? TRUE : FALSE; + pIoCtrl->u.uData[4] = (uReg & 0x00000001) ? TRUE : FALSE; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_ADV_THRESHOLD: + if (pIoCtrl->usLen == 12) { /* 1 + 2 + 1 + 4 * 2 */ + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL1); /* 0xE804 */ + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uReg &= 0x00ffffff; /* bit 31:24 */ + uReg |= (pIoCtrl->u.uData[0] & 0xff) << 24; + KS8695_WRITE_REG(KS8695_SWITCH_CTRL1, uReg); + DelayInMicroseconds(10); + + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + uReg &= 0x8fffffff; /* bit 30:28 */ + uReg |= (pIoCtrl->u.uData[1] & 0x07) << 28; + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = (uReg >> 24); + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + pIoCtrl->u.uData[1] = (uReg >> 28) & 0x07; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_ADV_DSCP: + if (pIoCtrl->usLen == 12) { /* 1 + 2 + 1 + 4 * 2 */ + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + /* DSCP high */ + KS8695_WRITE_REG(KS8695_DSCP_HIGH, pIoCtrl->u.uData[0]); + DelayInMicroseconds(10); + /* DSCP low */ + KS8695_WRITE_REG(KS8695_DSCP_LOW, pIoCtrl->u.uData[1]); + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = KS8695_READ_REG(KS8695_DSCP_HIGH); + pIoCtrl->u.uData[1] = KS8695_READ_REG(KS8695_DSCP_LOW); + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_INTERNAL_LED: + if (pIoCtrl->usLen == 12) { /* 1 + 2 + 1 + 4 * 2 */ + uint8_t byLed0, byLed1; + + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + byLed0 = (uint8_t)pIoCtrl->u.uData[0]; + byLed1 = (uint8_t)pIoCtrl->u.uData[1]; + if (byLed0 <= LED_LINK_ACTIVITY && byLed1 <= LED_LINK_ACTIVITY) { + swSetLED(Adapter, FALSE, byLed0); + swSetLED(Adapter, TRUE, byLed1); + + /* can we set WAN here as well or separate it to WAN driver ? */ + { + uReg = KS8695_READ_REG(KS8695_WAN_CONTROL); + uReg &= 0xffffff88; /* 6:4, 2:0 */ + uReg |= (uint32_t)byLed1 << 4; + uReg |= (uint32_t)byLed0; + KS8695_WRITE_REG(KS8695_WAN_CONTROL, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + } + else { /* out of range error */ + DRV_WARN("%s> LED setting out of range", __FUNCTION__); + break; + } + } + else { + /* note that currently, all LED use same settings, so there is no + need to define port in the IF */ + /* LAN */ + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + + pIoCtrl->u.uData[0] = (uint32_t)((uReg >> 22) & 0x7); + pIoCtrl->u.uData[1] = (uint32_t)((uReg >> 25) & 0x7); + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_INTERNAL_MISC: + if (pIoCtrl->usLen == 44) { /* 1 + 2 + 1 + 4 * 10 */ + uReg = KS8695_READ_REG(KS8695_SWITCH_CTRL0); + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + if (pIoCtrl->u.uData[0]) { + uReg |= SW_CTRL0_ERROR_PKT; + } + else { + uReg &= ~SW_CTRL0_ERROR_PKT; + } + if (pIoCtrl->u.uData[1]) { + uReg |= SW_CTRL0_BUFFER_SHARE; + } + else { + uReg &= ~SW_CTRL0_BUFFER_SHARE; + } + if (pIoCtrl->u.uData[2]) { + uReg |= SW_CTRL0_AGING_ENABLE; + } + else { + uReg &= ~SW_CTRL0_AGING_ENABLE; + } + if (pIoCtrl->u.uData[3]) { + uReg |= SW_CTRL0_FAST_AGING; + } + else { + uReg &= ~SW_CTRL0_FAST_AGING; + } + if (pIoCtrl->u.uData[4]) { + uReg |= SW_CTRL0_FAST_BACKOFF; + } + else { + uReg &= ~SW_CTRL0_FAST_BACKOFF; + } + if (pIoCtrl->u.uData[5]) { + uReg |= SW_CTRL0_6K_BUFFER; + } + else { + uReg &= ~SW_CTRL0_6K_BUFFER; + } + if (pIoCtrl->u.uData[6]) { + uReg |= SW_CTRL0_MISMATCH_DISCARD; + } + else { + uReg &= ~SW_CTRL0_MISMATCH_DISCARD; + } + if (pIoCtrl->u.uData[7]) { + uReg |= SW_CTRL0_COLLISION_DROP; + } + else { + uReg &= ~SW_CTRL0_COLLISION_DROP; + } + if (pIoCtrl->u.uData[8]) { + uReg |= SW_CTRL0_BACK_PRESSURE; + } + else { + uReg &= ~SW_CTRL0_BACK_PRESSURE; + } + if (pIoCtrl->u.uData[9]) { + uReg |= SW_CTRL0_PREAMBLE_MODE; + } + else { + uReg &= ~SW_CTRL0_PREAMBLE_MODE; + } + KS8695_WRITE_REG(KS8695_SWITCH_CTRL0, uReg); + /* need 20 cpu clock delay for switch related registers */ + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = uReg & SW_CTRL0_ERROR_PKT ? TRUE : FALSE; + pIoCtrl->u.uData[1] = uReg & SW_CTRL0_BUFFER_SHARE ? TRUE : FALSE; + pIoCtrl->u.uData[2] = uReg & SW_CTRL0_AGING_ENABLE ? TRUE : FALSE; + pIoCtrl->u.uData[3] = uReg & SW_CTRL0_FAST_AGING ? TRUE : FALSE; + pIoCtrl->u.uData[4] = uReg & SW_CTRL0_FAST_BACKOFF ? TRUE : FALSE; + pIoCtrl->u.uData[5] = uReg & SW_CTRL0_6K_BUFFER ? TRUE : FALSE; + pIoCtrl->u.uData[6] = uReg & SW_CTRL0_MISMATCH_DISCARD ? TRUE : FALSE; + pIoCtrl->u.uData[7] = uReg & SW_CTRL0_COLLISION_DROP ? TRUE : FALSE; + pIoCtrl->u.uData[8] = uReg & SW_CTRL0_BACK_PRESSURE ? TRUE : FALSE; + pIoCtrl->u.uData[9] = uReg & SW_CTRL0_PREAMBLE_MODE ? TRUE : FALSE; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_INTERNAL_SPANNINGTREE: + if (pIoCtrl->usLen == 20) { /* 1 + 2 + 1 + 4 * 4 */ + uint32_t uTxSpanning, uRxSpanning; + + uPort = pIoCtrl->u.uData[0]; + if (uPort >= SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + uTxSpanning = pIoCtrl->u.uData[1]; + uRxSpanning = pIoCtrl->u.uData[2]; + DPI[uPort].byDisableSpanningTreeLearn = pIoCtrl->u.uData[3]; + if (uTxSpanning) { + if (uRxSpanning) + DPI[uPort].bySpanningTree = SW_SPANNINGTREE_ALL; + else + DPI[uPort].bySpanningTree = SW_SPANNINGTREE_TX; + } + else { + if (uRxSpanning) + DPI[uPort].bySpanningTree = SW_SPANNINGTREE_RX; + else + DPI[uPort].bySpanningTree = SW_SPANNINGTREE_NONE; + } + swConfigurePort(Adapter, uPort); + } + else { + uTxSpanning = uRxSpanning = FALSE; + if (SW_SPANNINGTREE_ALL == DPI[uPort].bySpanningTree) { + uTxSpanning = uRxSpanning = TRUE; + } + else if (SW_SPANNINGTREE_TX == DPI[uPort].bySpanningTree) { + uTxSpanning = TRUE; + } + else if (SW_SPANNINGTREE_RX == DPI[uPort].bySpanningTree) { + uRxSpanning = TRUE; + } + pIoCtrl->u.uData[1] = uTxSpanning; + pIoCtrl->u.uData[2] = uRxSpanning; + pIoCtrl->u.uData[3] = (uint32_t)DPI[uPort].byDisableSpanningTreeLearn; + } + nRet = 0; + } + break; + +#ifdef CONFIG_ARCH_KS8695P + case CONFIG_SW_SUBID_PHY_IF: + if (pIoCtrl->usLen == 24) { /* 1 + 2 + 1 + 4 + 4 * 4 */ + u32 off, shift = 0; + + uPort = pIoCtrl->u.uData[0]; + if (DMA_WAN == DI.usDMAId) + uPort = 0; + if (uPort > SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + if (uPort == SW_MAX_LAN_PORTS) + off = KS8695_WAN_POWERMAGR; + else { + if (uPort < 2) + off = KS8695_LPPM12; + else + off = KS8695_LPPM34; + } + if (!(uPort % 2)) + shift = 1; + uReg = KS8695_READ_REG(off); + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + enablePhyLoopback(Adapter, uPort, pIoCtrl->u.uData[1]); + enableRemoteLoopback(Adapter, uPort, pIoCtrl->u.uData[2]); + enablePhyIsolate(Adapter, uPort, pIoCtrl->u.uData[3]); + forcePhyLink(Adapter, uPort, pIoCtrl->u.uData[4]); + } + else { + pIoCtrl->u.uData[1] = (uReg & (KS8695_LPPM_PHY_LOOPBACK << (shift * 16))) ? 1 : 0; + pIoCtrl->u.uData[2] = (uReg & (KS8695_LPPM_RMT_LOOPBACK << (shift * 16))) ? 1 : 0; + pIoCtrl->u.uData[3] = (uReg & (KS8695_LPPM_PHY_ISOLATE << (shift * 16))) ? 1 : 0; + pIoCtrl->u.uData[4] = (uReg & (KS8695_LPPM_FORCE_LINK << (shift * 16))) ? 1 : 0; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_SEC1: + if (pIoCtrl->usLen == 36) { /* 1 + 2 + 1 + 4 * 8 */ + uReg = KS8695_READ_REG(KS8695_SEC1); + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + if (pIoCtrl->u.uData[0]) + uReg |= KS8695_SEC1_NO_IEEE_AN; + else + uReg &= ~KS8695_SEC1_NO_IEEE_AN; + if (pIoCtrl->u.uData[1]) + uReg |= KS8695_SEC1_TPID_MODE; + else + uReg &= ~KS8695_SEC1_TPID_MODE; + if (pIoCtrl->u.uData[2]) + uReg |= KS8695_SEC1_NO_TX_8021X_FLOW_CTRL; + else + uReg &= ~KS8695_SEC1_NO_TX_8021X_FLOW_CTRL; + if (pIoCtrl->u.uData[3]) + uReg |= KS8695_SEC1_NO_RX_8021X_FLOW_CTRL; + else + uReg &= ~KS8695_SEC1_NO_RX_8021X_FLOW_CTRL; + if (pIoCtrl->u.uData[4]) + uReg |= KS8695_SEC1_HUGE_PACKET; + else + uReg &= ~KS8695_SEC1_HUGE_PACKET; + if (pIoCtrl->u.uData[5]) + uReg |= KS8695_SEC1_8021Q_VLAN_EN; + else + uReg &= ~KS8695_SEC1_8021Q_VLAN_EN; + if (pIoCtrl->u.uData[6]) + uReg |= KS8695_SEC1_MII_10BT; + else + uReg &= ~KS8695_SEC1_MII_10BT; + if (pIoCtrl->u.uData[7]) + uReg |= KS8695_SEC1_NULL_VID; + else + uReg &= ~KS8695_SEC1_NULL_VID; + KS8695_WRITE_REG(KS8695_SEC1, uReg); + DelayInMicroseconds(10); + } + else { + pIoCtrl->u.uData[0] = (uReg & KS8695_SEC1_NO_IEEE_AN) ? 1 : 0; + pIoCtrl->u.uData[1] = (uReg & KS8695_SEC1_TPID_MODE) ? 1 : 0; + pIoCtrl->u.uData[2] = (uReg & KS8695_SEC1_NO_TX_8021X_FLOW_CTRL) ? 1 : 0; + pIoCtrl->u.uData[3] = (uReg & KS8695_SEC1_NO_RX_8021X_FLOW_CTRL) ? 1 : 0; + pIoCtrl->u.uData[4] = (uReg & KS8695_SEC1_HUGE_PACKET) ? 1 : 0; + pIoCtrl->u.uData[5] = (uReg & KS8695_SEC1_8021Q_VLAN_EN) ? 1 : 0; + pIoCtrl->u.uData[6] = (uReg & KS8695_SEC1_MII_10BT) ? 1 : 0; + pIoCtrl->u.uData[7] = (uReg & KS8695_SEC1_NULL_VID) ? 1 : 0; + } + nRet = 0; + } + break; + + case CONFIG_SW_SUBID_GENERIC_DUMP: + if (pIoCtrl->usLen == 8) { /* 1 + 2 + 1 + 4 */ + int i; + + switch (pIoCtrl->u.uData[0]) { + case GENERIC_DUMP_DYNAMIC: + dumpDynamicMacTable(Adapter); + nRet = 0; + break; + + case GENERIC_DUMP_SWITCH_REGS: + printk("--Reg-- ---Value--\n"); + for (i = KS8695_SEC0; i <= KS8695_LPPM34; i += 4) { + printk(" 0x%04x 0x%08x\n", i, KS8695_READ_REG(i)); + } + nRet = 0; + break; + + case GENERIC_DUMP_STATIC: + dumpStaticMacTable(Adapter); + nRet = 0; + break; + + default: + case GENERIC_DUMP_VLAN: + DRV_INFO("%s> not implemented yet", __FUNCTION__); + break; + }; + } + break; + + case CONFIG_SW_SUBID_RATE_CTRL: + if (pIoCtrl->usLen == 32) { /* 1 + 2 + 4 * 7 */ + u32 off, tx, v1 = 0; + + uPort = pIoCtrl->u.uData[0]; + if (DMA_WAN == DI.usDMAId) + uPort = 0; + if (uPort > SW_MAX_LAN_PORTS) { + DRV_WARN("%s> LAN port out of range (%d)", __FUNCTION__, uPort); + break; + } + tx = pIoCtrl->u.uData[1]; + if (uPort == SW_MAX_LAN_PORTS) { + off = KS8695_SEP5C3; + if (tx) v1 = KS8695_READ_REG(KS8695_SEP5C2); + } else { + off = KS8695_SEP1C3 + uPort * 0x0c; + if (tx) v1 = KS8695_READ_REG(KS8695_SEP1C2 + uPort * 0x0c); + } + uReg = KS8695_READ_REG(off); + if (CONFIG_SWITCH_SET == pIoCtrl->byId) { + if (tx) { + setTxRate(Adapter, uPort, pIoCtrl->u.uData[2], pIoCtrl->u.uData[3]); + enableTxRateControl(Adapter, uPort, pIoCtrl->u.uData[4], pIoCtrl->u.uData[5], pIoCtrl->u.uData[6]); + } + else { + setRxRate(Adapter, uPort, pIoCtrl->u.uData[2], pIoCtrl->u.uData[3]); + enableRxRateControl(Adapter, uPort, pIoCtrl->u.uData[4], pIoCtrl->u.uData[5], pIoCtrl->u.uData[6]); + } + } + else { + if (tx) { + pIoCtrl->u.uData[2] = (v1 & KS8695_SEPC2_TX_L_RATECTRL_MASK); + pIoCtrl->u.uData[3] = ((v1 & KS8695_SEPC2_TX_H_RATECTRL_MASK) >> 12); + pIoCtrl->u.uData[4] = (uReg & KS8695_SEPC3_TX_DIF_RATECTRL_EN) ? 1 : 0; + pIoCtrl->u.uData[5] = (uReg & KS8695_SEPC3_TX_L_RATECTRL_EN) ? 1 : 0; + pIoCtrl->u.uData[6] = (uReg & KS8695_SEPC3_TX_H_RATECTRL_EN) ? 1 : 0; + } + else { + pIoCtrl->u.uData[2] = ((uReg & KS8695_SEPC3_RX_L_RATECTRL_MASK) >> 8); + pIoCtrl->u.uData[3] = ((uReg & KS8695_SEPC3_RX_H_RATECTRL_MASK) >> 20); + pIoCtrl->u.uData[4] = (uReg & KS8695_SEPC3_RX_DIF_RATECTRL_EN) ? 1 : 0; + pIoCtrl->u.uData[5] = (uReg & KS8695_SEPC3_RX_L_RATECTRL_EN) ? 1 : 0; + pIoCtrl->u.uData[6] = (uReg & KS8695_SEPC3_RX_H_RATECTRL_EN) ? 1 : 0; + } + } + nRet = 0; + } + break; +#endif + + default: + DRV_INFO("%s> unsupported parameters: id=%d, len=%d", __FUNCTION__, pIoCtrl->byId, pIoCtrl->usLen); + return -EOPNOTSUPP; + } + + return nRet; +} + +#ifdef __KS8695_CACHE_H +/* + * ks8695_icache_lock + * This function is use to lock given icache + * + * Argument(s) + * icache_start pointer to starting icache address + * icache_end pointer to ending icache address + * + * Return(s) + * 0 if success + * error otherwise + */ +int ks8695_icache_lock2(void *icache_start, void *icache_end) +{ + uint32_t victim_base = ICACHE_VICTIM_BASE << ICACHE_VICTIM_INDEX; + spinlock_t lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; +#ifdef DEBUG_THIS + int len; + + len = (int)(icache_end - icache_start); + DRV_INFO("%s: start=%p, end=%p, len=%d", __FUNCTION__, icache_start, icache_end, len); + /* if lockdown lines are more than half of max associtivity */ + if ((len / ICACHE_BYTES_PER_LINE) > (ICACHE_ASSOCITIVITY >> 1)) { + DRV_WARN("%s: lockdown lines = %d is too many, (Assoc=%d)", __FUNCTION__, (len / ICACHE_BYTES_PER_LINE), ICACHE_ASSOCITIVITY); + return -1; + } +#endif + + spin_lock_irqsave(&lock, flags); + + __asm__( + " \n\ + ADRL r0, ks8695_isr /* compile complains if icache_start is given instead */ \n\ + ADRL r1, ks8695_isre /* compile complains if icache_end is given instead */ \n\ + MOV r2, %0 \n\ + MCR p15, 0, r2, c9, c4, 1 \n\ + \n\ +lock_loop: \n\ + MCR p15, 0, r0, c7, c13, 1 \n\ + ADD r0, r0, #32 \n\ + \n\ + AND r3, r0, #0x60 \n\ + CMP r3, #0x0 \n\ + ADDEQ r2, r2, #0x1<<26 /* ICACHE_VICTIM_INDEX */ \n\ + MCREQ p15, 0, r2, c9, c0, 1 \n\ + \n\ + CMP r0, r1 \n\ + BLE lock_loop \n\ + \n\ + CMP r3, #0x0 \n\ + ADDNE r2, r2, #0x1<<26 /* ICACHE_VICTIM_INDEX */ \n\ + MCRNE p15, 0, r2, c9, c0, 1 \n\ + " + : + : "r" (victim_base) + : "r0", "r1", "r2", "r3" + ); + +#ifdef DEBUG_THIS + ks8695_icache_read_c9(); +#endif + + spin_unlock_irqrestore(&lock, flags); + + return 0; +} +#endif /*__KS8695_CACHE_H*/ + +#ifdef RX_TASK +/* + * ReceiveProcessTask + * This function is use to process Rx interrupt, send received data up + * the network stack. + * + * Argument(s) + * data pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE + */ +static void ReceiveProcessTask(uintptr_t data) +{ + PADAPTER_STRUCT Adapter = (PADAPTER_STRUCT)data; + UINT32 uFrameCtrl; + RXDESC *CurrentDescriptor; + +#ifdef DEBUG_THIS + DRV_INFO("%s> )", __FUNCTION__); +#endif + + /* + * Process receive packet by call ProcessRxInterrupts() + */ + ProcessRxInterrupts(Adapter); + + /* + * if there are pending rx interrupt, reschedule rx task again + */ + CurrentDescriptor = &DI.pRxDescriptors[DI.nRxDescNextAvail]; + uFrameCtrl = CurrentDescriptor->RxFrameControl; + if (!(uFrameCtrl & DESC_OWN_BIT)) + { +#ifdef TX_TASK + if (DI.nTransmitCount > (DI.nTxDescTotal >> 1)) { + /* try eanble read transfer again */ + KS8695_WRITE_REG(REG_TXSTART + DI.nOffset, 1); + if (FALSE == DI.tx_scheduled) { + DI.tx_scheduled = TRUE; + tasklet_hi_schedule(&DI.tx_tasklet); + } + } +#endif + tasklet_hi_schedule(&DI.rx_tasklet); + } + else + { + DI.rx_scheduled = FALSE; + /* enable corresponding Rx Interrupt again */ + KS8695_WRITE_REG(KS8695_INT_ENABLE, KS8695_READ_REG(KS8695_INT_ENABLE) | + ((uint32_t)INT_RX_BIT << DI.uIntShift)); + } +} + +#endif /*RX_TASK*/ + +#ifdef TX_TASK +/* + * TransmitProcessTask + * This function is use to process Tx interrupt in task level, reclaim resources after + * transmit completed. + * + * Argument(s) + * data pointer to ADAPTER_STRUCT structure. + * + * Return(s) + * NONE. + */ +static void TransmitProcessTask(uintptr_t data) +{ + PADAPTER_STRUCT Adapter = (PADAPTER_STRUCT)data; + + +#ifdef DEBUG_THIS + DRV_INFO("%s> )", __FUNCTION__); +#endif + + /* + * Process free transmit data buffer by call ProcessTxInterrupts() + */ + ProcessTxInterrupts(Adapter); + + + /* + * if there are pending tx interrupt, reschedule tx task again + */ +#ifndef USE_TX_UNAVAIL + if (KS8695_READ_REG(KS8695_INT_STATUS) & ((uint32_t)INT_TX_BIT << DI.uIntShift)) { +#else + if (KS8695_READ_REG(KS8695_INT_STATUS) & + ((uint32_t)(INT_TX_BIT | INT_TX_UNAVAIL_BIT) << DI.uIntShift) & DI.uIntMask) { +#endif + /* Acknowledge the transmit interrupt let this routine becomes + * an infinite loop. + */ + KS8695_WRITE_REG( KS8695_INT_STATUS, + ( uint32_t ) INT_TX_BIT << DI.uIntShift ); + tasklet_hi_schedule(&DI.tx_tasklet); + } + else + { + DI.tx_scheduled = FALSE; + /* enable corresponding Tx Interrupt again */ +#ifndef USE_TX_UNAVAIL + KS8695_WRITE_REG(KS8695_INT_ENABLE, KS8695_READ_REG(KS8695_INT_ENABLE) | + ((uint32_t)INT_TX_BIT << DI.uIntShift)); +#else + KS8695_WRITE_REG(KS8695_INT_ENABLE, KS8695_READ_REG(KS8695_INT_ENABLE) | + ((uint32_t)(INT_TX_BIT | INT_TX_UNAVAIL_BIT) << DI.uIntShift) & DI.uIntMask); +#endif + } + + + +} +#endif /*TX_TASK*/ + +/* ks8695_main.c */ diff --git a/drivers/net/mtip1000.c b/drivers/net/mtip1000.c new file mode 100644 index 00000000..42d42e2a --- /dev/null +++ b/drivers/net/mtip1000.c @@ -0,0 +1,2485 @@ +/*---------------------------------------------------------------------- + . mtip1000.c + . + . Driver: MoreThanIP 10/100/1000Mbps Emac IP + . + . Copyright (C) 2004 Microtronix Datacom 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. + * + . Sources: + . o MoreThanIP 10/100/1000Mbps Reference Guide V3.2 - May 2003 + . o MoreThanIP Altera Plugs sources + . - mtip_10_100_1000.c + . - mtip_10_100_1000_adapter.c + . - mac_stream_test.c + . o Smc9111 uClinux port(s) + . + . History: + . o Apr2004 DGT Microtronix Datacom - Linux 2.6.5 + . + -----------------------------------------------------------------------*/ + +static const char version[] = + "MoreThanIP 10/100/1000 Driver" + "(v1.0)" + ", Linux 2.6.5 Apr2004\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_EXCALIBUR + #include + #include + #include +#endif // CONFIG_EXCALIBUR + +#include +#include + +#include +#include +#include + +#include "mtip1000.h" +#include "stdphy.h" + +#define ANNOUNCEPHY +//#undef ANNOUNCEPHY + +//#undef MTIPPHYIRQ_AVAIL +#if 1 + #if defined (na_mii_irq_irq) + #define MTIPPHYIRQ_AVAIL + #define mtip_mii_control_port ((unsigned int *) (((unsigned int) (na_mii_irq)) | 0x80000000)) + #endif // na_mii_irq_irq +#else + #undef na_mii_irq_irq + #undef na_mii_irq +#endif + +//#define NS83865PHY +#define TDK78Q2120PHY + +#ifdef NS83865PHY + #include "ns83865phy.h" + #define PHYTYPE "NS83865" +#else + #ifdef TDK78Q2120PHY + #include "tdk78phy.h" + #define PHYTYPE "TDK78Q2120" + #endif +#endif + +#ifdef CONFIG_SYSCTL + #include + #include +#endif // CONFIG_SYSCTL + +//#undef na_dma // Force "Pio" mode +#if defined (na_dma) + #define MTIPDMA_AVAIL + #define mtip_dma_control_port ((np_dma *) (((unsigned int) (na_dma)) | 0x80000000)) + #define IOTYPE "DMA" + +#else + #undef MTIPDMA_AVAIL + #define IOTYPE "PIO" +#endif // na_dma + + +/*---------------------------------------------------------------------- + . DEBUGGING LEVELS + . + . 0 for normal operation + . 1 for slightly more details + . 2 for interrupt tracking, status flags + . 3 for packet info + . 4 for complete packet dumps + -----------------------------------------------------------------------*/ +//#define MTIP_DEBUG 4 +//#define MTIP_DEBUG 3 +//#define MTIP_DEBUG 2 +//#define MTIP_DEBUG 1 +#define MTIP_DEBUG 0 + +#if (MTIP_DEBUG > 2 ) + #define PRINTK3(args...) printk(args) +#else + #define PRINTK3(args...) +#endif + +#if MTIP_DEBUG > 1 + #define PRINTK2(args...) printk(args) +#else + #define PRINTK2(args...) +#endif + +#ifdef MTIP_DEBUG + #define PRINTK(args...) printk(args) +#else + #define PRINTK(args...) +#endif + + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long int dword; + + +/*----------------------------------------------------------- + Port address(es). Array must end in zero. +*/ +#if defined(CONFIG_EXCALIBUR) + static unsigned int mtip_portlist[] = + { ((int) + ((((unsigned int) (na_mtip_mac_control_port)) | 0x80000000))) + , 0 }; + static unsigned int mtip_irqlist[] = + { na_mtip_mac_rxFIFO_irq, 0 }; + #define PIO_port_rxFIFO (((unsigned int) (na_mtip_mac_rxFIFO)) | 0x80000000) + #define PIO_port_txFIFO (((unsigned int) (na_mtip_mac_txFIFO)) | 0x80000000) +#else + #define PIO_port_rxFIFO (((unsigned int) (na_mtip_mac_rxFIFO))) + #define PIO_port_txFIFO (((unsigned int) (na_mtip_mac_txFIFO))) + ............ +#endif // CONFIG_EXCALIBUR + + +struct mtip_local + { + struct net_device_stats stats; + +#ifdef CONFIG_SYSCTL + + // Root directory /proc/sys/dev + // Second entry must be null to terminate the table + ctl_table root_table[2]; + + // Directory for this device /proc/sys/dev/ethX + // Again the second entry must be zero to terminate + ctl_table eth_table[2]; + + // This is the parameters (file) table + ctl_table param_table[CTL_MTIP_LAST_ENTRY]; + + // Saves the sysctl header returned by register_sysctl_table() + // we send this to unregister_sysctl_table() + struct ctl_table_header *sysctl_header; + + // Parameter variables (files) go here + char ctl_info[1024]; // ?...? + +/* +....tbd............. + int ctl_xxxxxx's; +......................*/ + +#endif // CONFIG_SYSCTL + }; + + +/*----------------------------------------------------------- + | Print out a packet. +*/ +#if MTIP_DEBUG > 3 + static void print_packet( byte * buf, int length ) + { + #if 1 + #if MTIP_DEBUG > 3 + int i; + int remainder; + int lines; + #endif + + printk("Packet length %d \n", length ); + + #if MTIP_DEBUG > 3 + lines = length / 16; + remainder = length % 16; + + for ( i = 0; i < lines ; i ++ ) { + int cur; + + for ( cur = 0; cur < 8; cur ++ ) { + byte a, b; + + a = *(buf ++ ); + b = *(buf ++ ); + printk("%02x %02x ", a, b ); + } + printk("\n"); + } + for ( i = 0; i < remainder/2 ; i++ ) { + byte a, b; + + a = *(buf ++ ); + b = *(buf ++ ); + printk("%02x %02x ", a, b ); + } + printk("\n"); + #endif + #endif + } +#endif + + +/*----------------------------------------------------------- +*/ +#define PRINTSTDPHYREGS(pmac) \ + \ + printk(" PhyCtl0: %04X" \ + " PhySts1: %04X" \ + " PhyID1: %04X\n", \ + (pmac->mdio0).CONTROL, \ + (pmac->mdio0).STATUS, \ + (pmac->mdio0).PHY_ID1); \ + printk(" PhyID2: %04X" \ + " PhyAdv4: %04X" \ + " PhyRemcap5: %04X\n", \ + (pmac->mdio0).PHY_ID2, \ + (pmac->mdio0).ADV, \ + (pmac->mdio0).REMADV); + + +#ifdef NS83865PHY + #define PRINTNS83PHYREGS(pmac, \ + nsIntstsReg20, \ + nsIntieReg21, \ + nsLnkstsReg17) \ + \ + PRINTSTDPHYREGS(pmac); \ + \ + printk(" Ns20Ists:%04X" \ + " Ns21Intie:%04X" \ + " Ns17Lnksts: %04X\n", \ + nsIntstsReg20, \ + nsIntieReg21, \ + nsLnkstsReg17); +#endif + + +#ifdef TDK78Q2120PHY + #define PRINTTDKPHYREGS(pmac, \ + tdkintCtlStsReg17, \ + tdkDiagReg18) \ + \ + PRINTSTDPHYREGS(pmac); \ + \ + printk(" Tdk16: %04X" \ + " Tdk17Int: %04X" \ + " Tdk18Diag: %04X\n", \ + (pmac->mdio0).reg10, \ + tdkintCtlStsReg17, \ + tdkDiagReg18); +#endif + + +/*----------------------------------------------------------- +*/ +unsigned int gMtipDisabledRxints; +unsigned int gMtipDisabledTxints; +unsigned long gMtipDiscardSink; // RxFifo discard +unsigned int gMtipDmaints; +unsigned int gMtipDmaintsBusy; +unsigned int gMtipDmaintsBusyDone; +unsigned int gMtipDmaintsNoDone; +unsigned int gMtipRxints; +unsigned int gMtipRxintsRxdmaBusy; +unsigned int gMtipRxintsRxdmaQued; +unsigned int gMtipRxNoints; +int gMtipRxSkbFifoNumL32s; +word gMtipRxSkbframelenbyts; +unsigned int gMtipTxints; +unsigned int gMtipTxintsIncomplete; +int gMtipTxSkbFifoNumL32s; +word gMtipTxSkbframelenbyts; +unsigned int gMtipUnexpDmaints; +unsigned int gMtipUnexpRxints; +unsigned int gMtipUnexpTxints; +byte *gpMtipRxData; +struct sk_buff *gpMtipRxSkbInProg; +byte *gpMtipTxData; +struct sk_buff *gpMtipTxSkbInProg; + +#if defined (MTIPDMA_AVAIL) + +unsigned int gMtipDmaQ; +unsigned int gMtipDmaState; + +unsigned char gMtipTmpDmaBuf[MTIP_MAC_MAX_FRAME_SIZE + MTIP_MI_XBUF_BYTS]; + // Nios alignment requirements...very inconvenient... + // for now...but should be in "on chip sram" if any... + // (perhaps used as "ring[s]"... + // for now...rx and tx share same temporary 1 only "dma buffer" + +enum + { + Mtip_DmaQ_TxSkb2Tmp = (1 << 0) + , Mtip_DmaQ_RxFifo2Tmp = (1 << 1) + , Mtip_DmaQ_RxFifo2Trash = (1 << 2) + }; + +enum + { + Mtip_DmaState_Idle = 0 + , Mtip_DmaState_RxFifo2Tmp = 1 + , Mtip_DmaState_RxTmp2Skb = 2 + , Mtip_DmaState_TxSkb2Tmp = 3 + , Mtip_DmaState_TxTmp2Fifo = 4 + , Mtip_DmaState_RxFifo2Trash = 5 + }; + + +/*----------------------------------------------------------- +*/ +static void dma_start + (int bytes_per_transfer, + void *source_address, + void *destination_address, + int transfer_count, // In units of bytes_per_transfer + int mode) // wcon, rcon, i_en, ... bit(s) + { + // Caller must have already flushed any "memory" range + // involved in this transfer that stands at risk. + + int control_bits = 0; + np_dma *dma = mtip_dma_control_port; + + dma->np_dmacontrol = 0; + // | 1. Halt anything that's going on + + dma->np_dmastatus = 0; + dma->np_dmareadaddress = (int)source_address; + dma->np_dmawriteaddress = (int)destination_address; + dma->np_dmalength = transfer_count * bytes_per_transfer; + + control_bits = + mode + | (bytes_per_transfer & 7) // low three bits of control reg + | ((bytes_per_transfer & 8) ? np_dmacontrol_doubleword_mask : 0) + | ((bytes_per_transfer & 16) ? np_dmacontrol_quadword_mask : 0) + | np_dmacontrol_leen_mask // enable length +// | np_dmacontrol_reen_mask //;dgt;tmp;test; Enable read end-of-packet +// | np_dmacontrol_ween_mask //;dgt;tmp;test; Enable write end-of-packet + | np_dmacontrol_go_mask; // and... go! + + dma->np_dmacontrol = control_bits; + + return; + } + +/*----------------------------------------------------------- +*/ +void dma_start_RxFifo2Tmp(void) + { + // Caller must have already set gMtipDmaState + // to Mtip_DmaState_RxFifo2Tmp (under semaphore), + // and disabled Rx ready interrupts. + + dcache_push (((unsigned long) (gpMtipRxData)), + gMtipRxSkbframelenbyts); + + dma_start + (4, // Byts per transfer + ((void *) (na_mtip_mac_rxFIFO)), // 32 bit source fifo + gMtipTmpDmaBuf, // 32 bit aligned dest + gMtipRxSkbFifoNumL32s, // # of 4 byte transfers + ( np_dmacontrol_rcon_mask // Source is a Fifo + | np_dmacontrol_i_en_mask // Dma done:interrupt + )); + } + +/*----------------------------------------------------------- +*/ +void dma_start_TxSkb2Tmp(void) + { + // Caller must have already set gMtipDmaState + // to Mtip_DmaState_TxSkb2Tmp (under semaphore) + + dcache_push (((unsigned long) (gpMtipTxData)), + gMtipTxSkbframelenbyts); + dma_start + (2, // Byts per transfer + gpMtipTxData, // 16 bit aligned src, + gMtipTmpDmaBuf, // 32 bit aligned dest, + (gMtipTxSkbFifoNumL32s << 1), // # of 2 byte transfers + ( 0 // Neither end a fifo + | np_dmacontrol_i_en_mask // Dma done:interrupt + )); + // At the risk of possibly incurring twice the copy + // time, save some cpu cycles by assuming outbound + // data starts on a 16 bit boundary (Have never + // empirically observed it on anything but...)... + } + +/*----------------------------------------------------------- +*/ +void dma_start_RxFifo2Trash(void) + { + // Caller must have already set gMtipDmaState + // to Mtip_DmaState_RxFifo2Trash (under semaphore), + // and disabled Rx ready interrupts. + + dma_start + (4, // Byts per transfer + ((void *) (na_mtip_mac_rxFIFO)), // 32 bit source fifo + ((unsigned char *) + &(gMtipDiscardSink)), // 32 bit aligned dest + gMtipRxSkbFifoNumL32s, // # of 4 byte transfers + ( np_dmacontrol_rcon_mask // Source is a Fifo + | np_dmacontrol_wcon_mask // Dest is a sinkhole + | np_dmacontrol_i_en_mask // Dma done:interrupt + )); + } +#endif // MTIPDMA_AVAIL + +/*----------------------------------------------------------- + | Entry condition: Cpu interrupts DISabled. +*/ +static void mtip_NuRxReady(struct net_device *dev, + unsigned int cmplnstatus) + { + // Caller must have already verified cmplnstatus's + // mmac_rcs_VALID_mask bit is SET. + + struct mtip_local *lp; + np_mtip_mac *pmac; + + lp = (struct mtip_local *)dev->priv; + pmac = ((np_mtip_mac *) dev->base_addr); + + gMtipRxSkbframelenbyts = ( cmplnstatus & mmac_rcs_FRAME_LENGTH_mask ); + + PRINTK3 +// printk + ( + "mtip_NuRxReady:%s, asts:0x%04X, csts:0x%08X, Len:%d\n", + dev->name, + pmac->AVL_STATUS, + cmplnstatus, + gMtipRxSkbframelenbyts); + + if(gMtipRxSkbframelenbyts == 0) + { +// PRINTK3 + printk + ( + "mtip_NuRxReady:%s, ZERO len frame," + " asts:0x%04X, csts:0x%08X\n", + dev->name, + pmac->AVL_STATUS, + cmplnstatus); + } + + gMtipRxSkbFifoNumL32s = ((gMtipRxSkbframelenbyts + 3) >> 2); + + if( cmplnstatus & mmac_rcs_ERROR_mask ) + { + PRINTK3 +// printk + ( + "mtip_NuRxReady:%s, Bad frame:0x%08X, Len:%d\n", + dev->name, + cmplnstatus, + gMtipRxSkbframelenbyts); + + lp->stats.rx_errors++; + + //;...can't differentiate...lp->stats.rx_frame_errors++; + //;...can't differentiate...lp->stats.rx_length_errors++; + //;...can't differentiate...lp->stats.rx_crc_errors++; + + #if defined (MTIPDMA_AVAIL) + pmac->IRQ_CONFIG &= (~(mmac_ic_EN_RX_FRAME_AVAILABLE_mask)); + // disable rx ready interrupt + + if(gMtipDmaState == Mtip_DmaState_Idle) + { + gMtipDmaState = Mtip_DmaState_RxFifo2Trash; + + dma_start_RxFifo2Trash(); + } + else + { + gMtipDmaQ |= Mtip_DmaQ_RxFifo2Trash; + } + + return; + #else + { + int FifoL32 = 0; + pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + while( (pmac->RX_CMD_STAT) & mmac_rcs_READ_CMD_mask ) + { + FifoL32 |= *((volatile unsigned long *) PIO_port_rxFIFO); + } + gMtipDiscardSink = FifoL32; + } + + return; + #endif // MTIPDMA_AVAIL + } + + //;...?...lp->stats.multicast++; + + if(gMtipRxSkbframelenbyts > MTIP_MAC_MAX_FRAME_SIZE) + { +// PRINTK3 + printk + ( +// KERN_NOTICE + "mtip_NuRxReady:%s, oversized %d byte packet.\n", + dev->name, + gMtipRxSkbframelenbyts); + goto Dropfrm_label; + } + + gpMtipRxSkbInProg = + dev_alloc_skb( (gMtipRxSkbFifoNumL32s << 2) + + MTIP_SKB_XBUF_BYTS ); + // Extra bytes: Dma requirements + + if ( gpMtipRxSkbInProg == NULL ) + { + PRINTK3 +// printk + ( +// KERN_NOTICE + "mtip_NuRxReady:%s, Low memory, packet dropped.\n", + dev->name); + goto Dropfrm_label; + } + + skb_reserve( gpMtipRxSkbInProg, 2 ); /* 16 bit alignment */ + + gpMtipRxSkbInProg->dev = dev; + + gpMtipRxData = skb_put( gpMtipRxSkbInProg, gMtipRxSkbframelenbyts ); + + lp->stats.rx_packets++; + + #if defined (MTIPDMA_AVAIL) + pmac->IRQ_CONFIG &= (~(mmac_ic_EN_RX_FRAME_AVAILABLE_mask)); + // disable rx ready interrupt + + if(gMtipDmaState == Mtip_DmaState_Idle) + { + gMtipDmaState = Mtip_DmaState_RxFifo2Tmp; + + dma_start_RxFifo2Tmp(); + } + else + { + gMtipDmaQ |= Mtip_DmaQ_RxFifo2Tmp; + } + + return; + #else + insl(((unsigned long) PIO_port_rxFIFO), + gpMtipRxData, + gMtipRxSkbFifoNumL32s); + + PRINTK3 + ( + "%s:Received %d byte Packet 0x%08X\n", + dev->name, + gMtipRxSkbframelenbyts, + ((unsigned long) gpMtipRxData)); + + #if MTIP_DEBUG > 3 + print_packet( gpMtipRxData, gMtipRxSkbframelenbyts ); + #endif + + gpMtipRxSkbInProg->protocol = + eth_type_trans(gpMtipRxSkbInProg, dev ); + + netif_rx(gpMtipRxSkbInProg); + + pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + // acknowledge frame reception + + return; + #endif // MTIPDMA_AVAIL + +Dropfrm_label: + + /* Oversized Rx frame, or dev_alloc_skb(...) failure */ + + lp->stats.rx_dropped++; + + #if defined (MTIPDMA_AVAIL) + pmac->IRQ_CONFIG &= (~(mmac_ic_EN_RX_FRAME_AVAILABLE_mask)); + // disable rx ready interrupt + + if(gMtipDmaState == Mtip_DmaState_Idle) + { + gMtipDmaState = Mtip_DmaState_RxFifo2Trash; + + dma_start_RxFifo2Trash(); + } + else + { + gMtipDmaQ |= Mtip_DmaQ_RxFifo2Trash; + } + + return; + #else + { + int FifoL32 = 0; + int FifoLoop; + for ( FifoLoop = 0; FifoLoop < gMtipRxSkbFifoNumL32s ; FifoLoop++ ) + { + FifoL32 |= *((volatile unsigned long *) PIO_port_rxFIFO); + } + gMtipDiscardSink = FifoL32; + } + + pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + // acknowledge frame reception + + return; + #endif // MTIPDMA_AVAIL + } + +#if defined (MTIPDMA_AVAIL) +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t mtip_DmaInterrupt(int irq, + void *dev_id, + struct pt_regs *regs) + { + unsigned int cmplnstatus; + struct net_device *dev = dev_id; + np_dma *dma = mtip_dma_control_port; + int old_dmastatus; + np_mtip_mac *pmac; + + ++gMtipDmaints; + + pmac = ((np_mtip_mac *) dev->base_addr); + old_dmastatus = dma->np_dmastatus; + + if(old_dmastatus & np_dmastatus_busy_mask) + { + ++gMtipDmaintsBusy; + + if(old_dmastatus & np_dmastatus_done_mask) + { + ++gMtipDmaintsBusyDone; + } + + return IRQ_HANDLED; + // ...This could be interesting...! + } + + if(!(old_dmastatus & np_dmastatus_done_mask)) + { + ++gMtipDmaintsNoDone; + // presumably gMtipDmaState .eq. Mtip_DmaState_Idle + } + + dma->np_dmastatus = 0; // Clear done bit (and ack the interrupt) + + switch (gMtipDmaState) + { + case Mtip_DmaState_RxFifo2Tmp: + + pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + // acknowledge frame reception + + gMtipDmaState = Mtip_DmaState_RxTmp2Skb; + dma_start + (2, // Byts per transfer + gMtipTmpDmaBuf, // 32 bit aligned src + gpMtipRxData, // 16 bit aligned dest + (gMtipRxSkbFifoNumL32s << 1), // # of 2 byte transfers + ( 0 // Neither end a fifo + | np_dmacontrol_i_en_mask // Dma done:interrupt + )); + + goto DmaIntExit_label; + + case Mtip_DmaState_RxTmp2Skb: + +//;see state RxFifo2Tmp; pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + // acknowledge frame reception + + PRINTK3 + ( + "%s:Received %d byte Packet 0x%08X\n", + dev->name, + gMtipRxSkbframelenbyts, + ((unsigned long) gpMtipRxData)); + + #if MTIP_DEBUG > 3 + print_packet( gpMtipRxData, gMtipRxSkbframelenbyts ); + #endif + + gpMtipRxSkbInProg->protocol = + eth_type_trans(gpMtipRxSkbInProg, dev ); + + netif_rx(gpMtipRxSkbInProg); + + pmac->IRQ_CONFIG |= mmac_ic_EN_RX_FRAME_AVAILABLE_mask; + // enable rx ready interrupt + // Note DmaMaybe2Idle_label will find NEITHER + // of gMtipDmaQ's Mtip_DmaQ_RxFifo2Tmp NOR + // Mtip_DmaQ_RxFifo2Trash bits set! + + goto DmaMaybe2Idle_label; + + case Mtip_DmaState_TxSkb2Tmp: + + gMtipDmaState = Mtip_DmaState_TxTmp2Fifo; + pmac->TX_CMD_STAT = (gMtipTxSkbframelenbyts | + mmac_tcs_FRAME_COMPLETE_mask); + dma_start + (4, // Byts per transfer + gMtipTmpDmaBuf, // 32 bit aligned src + ((void *) (na_mtip_mac_txFIFO)), // 32 bit dest fifo + gMtipTxSkbFifoNumL32s, // # of 4 byte transfers + ( np_dmacontrol_wcon_mask // Dest is a Fifo + | np_dmacontrol_i_en_mask // Dma done:interrupt + )); + + goto DmaIntExit_label; + + case Mtip_DmaState_TxTmp2Fifo: + + pmac->IRQ_CONFIG |= mmac_ic_EN_TX_FIFO_EMPTY_mask; + // enable tx done interrupt + + goto DmaMaybe2Idle_label; + + case Mtip_DmaState_RxFifo2Trash: + + pmac->RX_CMD_STAT = mmac_rcs_READ_CMD_mask; + // acknowledge frame reception + + pmac->IRQ_CONFIG |= mmac_ic_EN_RX_FRAME_AVAILABLE_mask; + // enable rx ready interrupt + // Note DmaMaybe2Idle_label will find NEITHER + // of gMtipDmaQ's Mtip_DmaQ_RxFifo2Tmp NOR + // Mtip_DmaQ_RxFifo2Trash bits set! + goto DmaMaybe2Idle_label; + +// case Mtip_DmaState_Idle: + default: + + ++gMtipUnexpDmaints; + + PRINTK3 +// printk + ( + "mtip_DmaInterrupt:%s," + " Unexpected state:0x%02X" + " (sts:0x%02X," + " ctl:0x%04X)\n", + dev->name, + gMtipDmaState, + dma->np_dmastatus, + dma->np_dmacontrol); + + // fall thru to DmaMaybe2Idle_label + } + +DmaMaybe2Idle_label: + + if(gMtipDmaQ & Mtip_DmaQ_TxSkb2Tmp) + { + gMtipDmaQ &= (~(Mtip_DmaQ_TxSkb2Tmp)); + + gMtipDmaState = Mtip_DmaState_TxSkb2Tmp; + + dma_start_TxSkb2Tmp(); + } + else if (gMtipDmaQ & Mtip_DmaQ_RxFifo2Tmp) + { + gMtipDmaQ &= (~(Mtip_DmaQ_RxFifo2Tmp)); + + gMtipDmaState = Mtip_DmaState_RxFifo2Tmp; + + dma_start_RxFifo2Tmp(); + } + else if (gMtipDmaQ & Mtip_DmaQ_RxFifo2Trash) + { + gMtipDmaQ &= (~(Mtip_DmaQ_RxFifo2Trash)); + + gMtipDmaState = Mtip_DmaState_RxFifo2Trash; + + dma_start_RxFifo2Trash(); + } + else + { + gMtipDmaState = Mtip_DmaState_Idle; + + if(( (pmac->AVL_STATUS) & (mmac_as_RX_FRAME_AVAILABLE_mask) )) + { + cmplnstatus = pmac->RX_CMD_STAT; + if(( cmplnstatus & mmac_rcs_VALID_mask )) + { + ++gMtipRxNoints; + + mtip_NuRxReady(dev, cmplnstatus); + // mtip_NuRxReady (re)disables Rx interrupts... + } + } + } + +DmaIntExit_label: + + return IRQ_HANDLED; + } +#endif // MTIPDMA_AVAIL + + +#ifdef CONFIG_SYSCTL +/*----------------------------------------------------------- + | +*/ +static const char mtip_info_string[] = +"\n" +"info Provides this information blurb\n" +".... Remind author to complete\n" +" ... ...\n" +".... Remind author to complete\n" +""; +#endif /* endif CONFIG_SYSCTL */ + + +#ifdef CONFIG_SYSCTL +/*----------------------------------------------------------- + | Sysctl handler for all integer parameters +*/ +static int mtip_sysctl_handler(ctl_table *ctl, + int write, + struct file *filp, + void *buffer, + size_t *lenp) +{ + int ret; + + ret = 0; +/* +....tbd............. +.....................*/ + + return ret; +} +#endif /* endif CONFIG_SYSCTL */ + + +#ifdef CONFIG_SYSCTL +/*----------------------------------------------------------- + | Sysctl registration function for all parameters (files) + | + | Initilizes device's sysctl proc filesystem + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_sysctl_register(struct net_device *dev) +{ + struct mtip_local *lp = (struct mtip_local *)dev->priv; + static int ctl_name = CTL_MTIP1000; + ctl_table* ct; + int i; + + // Make sure the ctl_tables start out as all zeros + memset(lp->root_table, 0, sizeof lp->root_table); + memset(lp->eth_table, 0, sizeof lp->eth_table); + memset(lp->param_table, 0, sizeof lp->param_table); + + // Initialize the root table + ct = lp->root_table; + ct->ctl_name = CTL_DEV; + ct->procname = "dev"; + ct->maxlen = 0; + ct->mode = 0555; + ct->child = lp->eth_table; + // remaining fields are zero + + // Initialize the ethX table (this device's table) + ct = lp->eth_table; + ct->ctl_name = ctl_name++; // Must be unique + ct->procname = dev->name; + ct->maxlen = 0; + ct->mode = 0555; + ct->child = lp->param_table; + // remaining fields are zero + + // Initialize the parameter (files) table + // Make sure the last entry remains null + ct = lp->param_table; + for (i = 0; i < (CTL_MTIP_LAST_ENTRY-1); ++i) + { + // Initialize fields common to all table entries + ct[i].proc_handler = mtip_sysctl_handler; + ct[i].extra1 = (void*)dev; // Save our device pointer + ct[i].extra2 = (void*)lp; // Save our mtip_local data pointer + } + + // INFO - this is our only string parameter + i = 0; + ct[i].proc_handler = proc_dostring; // use default handler + ct[i].ctl_name = CTL_MTIP_INFO; + ct[i].procname = "info"; + ct[i].data = (void*)mtip_info_string; + ct[i].maxlen = sizeof mtip_info_string; + ct[i].mode = 0444; // Read only + + // SWVER + ++i; + ct[i].proc_handler = proc_dostring; // use default handler + ct[i].ctl_name = CTL_MTIP_SWVER; + ct[i].procname = "swver"; + ct[i].data = (void*)version; + ct[i].maxlen = sizeof version; + ct[i].mode = 0444; // Read only + +/* +....tbd............. +.....................*/ + #ifdef MTIP_DEBUG +/* +....tbd............. +.....................*/ + #endif // MTIP_DEBUG + + // Register /proc/sys/dev/ethX + lp->sysctl_header = register_sysctl_table(lp->root_table, 1); +} +#endif /* endif CONFIG_SYSCTL */ + + +#ifdef CONFIG_SYSCTL +/*----------------------------------------------------------- + | Sysctl unregistration when driver closed +*/ +static void mtip_sysctl_unregister(struct net_device *dev) +{ + struct mtip_local *lp = (struct mtip_local *)dev->priv; + + unregister_sysctl_table(lp->sysctl_header); +} +#endif /* endif CONFIG_SYSCTL */ + + +void mtip_phymac_synch (struct net_device *dev, int callerflg) + { + unsigned long cmdcfg; + unsigned long phy100mbitflg; + unsigned long phyfulldupflg; + unsigned long phymr1sts; + unsigned long phyanegfailedflg; + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + phymr1sts = (pmac->mdio0).STATUS; + /* Read twice to get CURRENT status...?... */ + phymr1sts = (pmac->mdio0).STATUS; + + cmdcfg = pmac->COMMAND_CONFIG; + + #ifdef NS83865PHY + unsigned long phymr17linkan; + + phymr17linkan = (pmac->mdio0).reg11; + + phy100mbitflg = (phymr17linkan & 0x0008); + phyfulldupflg = (phymr17linkan & 0x0002); + + phyanegfailedflg = (((pmac->mdio0).reg14) & 0x0100); + #else + #if defined(TDK78Q2120PHY) + { + unsigned long phymr18diag; + + phymr18diag = (pmac->mdio0).reg12; + + phy100mbitflg = (phymr18diag & 0x0400); + phyanegfailedflg = (phymr18diag & 0x1000); + phyfulldupflg = (phymr18diag & 0x0800); + } + #else + ...?... + ...?... + #endif // TDK78Q2120PHY + #endif // NS83865PHY + + if(callerflg == 0) + { + // Caller = NOT Phy interrupt handler + + if((phymr1sts & 0x00000004) != 0) + { + // Link is ostensibly OK + + if((((pmac->mdio0).CONTROL) & 0x00001000) != 0) + { + // Auto negotiation ostensibly enabled + + if((phymr1sts & 0x00000020) != 0) + { + // Auto negotiation ostensibly has completed + + if(phyanegfailedflg) + { + // Auto negotiation ostensibly has failed + + if(phy100mbitflg | phyfulldupflg) + { + // Auto negotiation failure expected to + // have fallen back to 10 mbit half + // duplex - perhaps phy registers aren't + // actually available, and we've been + // reading 0xFFFF's... + + // A 10 mbit, 1/2 duplex remote partner + // mandates a 1/2 duplex Emac (else any + // amount of traffic at all will almost + // certainly collide up a storm...) + // 100 mbit remote partners seem to allow + // duplex mismatches without severe + // loss, at least at the low end of + // their nominal capacity. + // A 10 mbit, full duplex remote partner + // probably also requires a matched Emac, + // but hasn't been confirmed... + + printk("\nmtip_phymac_synch:%s" + " No phyregs?-assuming HalfD\n", + dev->name); + + pmac->COMMAND_CONFIG |= mmac_cc_HD_ENA_mask; + + if((pmac->COMMAND_CONFIG & + mmac_cc_HD_ENA_mask) == 0) + { + printk("\nmtip_phymac_synch:%s" + " HalfD phy, but FullD emac\n", + dev->name); + } + + return; + } + } + } + } + } + } +// else +// { +// // Caller = Phy interrupt handler +// // If we've got a phy interrupt, then we're so likely +// // to also have actual phy registers that we won't +// // bother trying to confirm... +// } + + #if defined(ANNOUNCEPHY) + printk("\nmtip_phymac_synch:%s MR1: 0x%08lX\n", + dev->name, + phymr1sts); + if((phymr1sts & 0x00000002) != 0) + { + printk(" Jabber\n"); + } + if((phymr1sts & 0x00000010) != 0) + { + printk(" Remote Fault\n"); + } + if((phymr1sts & 0x00000020) != 0) + { + printk(" Autoneg'd\n"); + } + #endif + + if((phymr1sts & 0x00000004) != 0) + { + /* Phy MR1 (status register) indicates link is (now) OK. */ + + #if defined(ANNOUNCEPHY) + printk(" Link OK:\n"); + #endif + + if(phyfulldupflg) + { + /* Link is (now) running full duplex. */ + + pmac->COMMAND_CONFIG = (cmdcfg & + (~(mmac_cc_HD_ENA_mask))); + + #if defined(ANNOUNCEPHY) + printk(" FullD\n"); + #endif + } + else + { + /* Link is (now) running half duplex. */ + + pmac->COMMAND_CONFIG = (cmdcfg | mmac_cc_HD_ENA_mask); + + if((pmac->COMMAND_CONFIG & mmac_cc_HD_ENA_mask) == 0) + { + printk("\nmtip_phymac_synch:%s" + " HalfD phy, but FullD emac\n", + dev->name); + } + + #if defined(ANNOUNCEPHY) + printk(" HalfD\n"); + #endif + } + + #if defined(ANNOUNCEPHY) + printk(" %s\n", + (phy100mbitflg) ? "100BASE-TX" : "10BASE-T"); + #endif + } + #if defined(ANNOUNCEPHY) + else + { + printk(" Link Down\n"); + + // ...what if link comes up without a phy interrupt + // ... and the emac/phy duplexs don't match...?... + } + #endif + + #if defined(ANNOUNCEPHY) + printk(" CMDCF: 0x%08X\n", + pmac->COMMAND_CONFIG); + printk("\n"); + #endif + + return; + } + + +/*----------------------------------------------------------- + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_phy_configure(struct net_device* dev) + { + /* No need to (re)configure advertisement register or (re)start */ + /* auto negotiation after the reset that our caller has probably */ + /* recently performed if auto negotiation is enabled by default */ + /* and all capabilities are to be advertised. Advertisement */ + /* register has already defaulted to our capabilities on last */ + /* reset, and phy automatically renegotiates when reset, and/or */ + /* when link comes (back) up, etc. */ + + /* If phy interrupts are required, DO need to reconfigure the */ + /* phy's interrupt control register after the reset our caller */ + /* has probably recently performed. */ + + unsigned int msecswaited; + unsigned int my_ad_caps; // My Advertised capabilities + unsigned int my_phy_caps; // My PHY capabilities + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + my_ad_caps = PHY_ADV_CSMA; + my_phy_caps = (pmac->mdio0).STATUS; + + /* Note Mx TDK phy board's (9) switches control its inherrent */ + /* capabilibles (at the moment, prototype:all off = */ + /* all capabilities available).. */ + + if(my_phy_caps & (PHY_STS_CAP_TXF_MASK)) + { +// if(..we're allowing 100mbit full duplex...) + { + my_ad_caps |= PHY_ADV_TX_FDX; + } + } + + if(my_phy_caps & (PHY_STS_CAP_TXH_MASK)) + { +// if(..we're allowing 100mbit half duplex...) + { + my_ad_caps |= PHY_ADV_TX_HDX; + } + } + + if(my_phy_caps & (PHY_STS_CAP_TF_MASK)) + { +// if(..we're allowing 10mbit full duplex...) + { + my_ad_caps |= PHY_ADV_10_FDX; + } + } + + if(my_phy_caps & (PHY_STS_CAP_TH_MASK)) + { +// if(..we're allowing 10mbit half duplex...) + { + my_ad_caps |= PHY_ADV_10_HDX; + } + } + + (pmac->mdio0).ADV = my_ad_caps; + + #if defined (MTIPPHYIRQ_AVAIL) + #ifdef NS83865PHY + (pmac->mdio0).reg15 = + ( 0 + | NS883865_INTIE_ANEGDONE_MASK + | NS883865_INTIE_LSCHG_MASK + ); + #else + #ifdef TDK78Q2120PHY + (pmac->mdio0).reg11 = + ( 0 + | TDK78_INTIE_ANEGDONE_MASK + | TDK78_INTIE_LSCHG_MASK +// | TDK78_INTIE_RXER_MASK + ); + #else + ...... + #endif // TDK78Q2120PHY + #endif // NS83865PHY + #endif // MTIPPHYIRQ_AVAIL + + (pmac->mdio0).CONTROL = + ( 0 + | PHY_CTL_ANEG_EN_MASK + | PHY_CTL_ANEG_RST_MASK + ); + + msecswaited = 0; + while(((((pmac->mdio0).STATUS) & 0x00000020) == 0) & + (msecswaited < 15000)) + { + mdelay(100); + msecswaited += 100; + } + + #if 1 + if((((pmac->mdio0).STATUS) & 0x00000020) != 0) + { + printk("mtip_phy_configure:%s, autoneg complete\n", + dev->name); + } + else + { + printk("mtip_phy_configure:%s, autoneg started\n", + dev->name); + } + + #ifdef NS83865PHY + PRINTNS83PHYREGS(pmac, + ((unsigned int) ((pmac->mdio0).reg14)), + ((unsigned int) ((pmac->mdio0).reg15)), + ((unsigned int) ((pmac->mdio0).reg11))); + #else + #ifdef TDK78Q2120PHY + PRINTTDKPHYREGS(pmac, + ((unsigned int) ((pmac->mdio0).reg11)), + ((unsigned int) ((pmac->mdio0).reg12))); + #else + ...... + #endif + #endif + #endif + } + + +/*----------------------------------------------------------- + | Enable Receive and Transmit, and Rx Interrupts + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_enable( struct net_device *dev ) +{ + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + PRINTK2("%s:mtip_enable\n", dev->name); + + pmac->COMMAND_CONFIG = + ( mmac_cc_TX_ENA_mask // enable transmit + | mmac_cc_RX_ENA_mask // enable receive + | mmac_cc_TX_ADDR_INS_mask // always overwrite source MAC addr + ); + + pmac->IRQ_CONFIG = mmac_ic_EN_RX_FRAME_AVAILABLE_mask; + // enable rx ready interrupt + + #if defined (MTIPPHYIRQ_AVAIL) + #if defined (na_mii_irq) + (*(volatile unsigned long *) + (((unsigned long *) + ((((char *) + (((int) (mtip_mii_control_port)) + + 0x0008))))))) = + ((unsigned long) (0x0001)); + // Enable phy interrupt pass thru to na_mii_irq + #endif // na_mii_irq + #endif // MTIPPHYIRQ_AVAIL +} + + +/*----------------------------------------------------------- + | Perform a software Reset. + | Takes some time so we need to wait until it is finshed. + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_mac_SwReset( struct net_device* dev ) + { +//// struct mtip_local *lp = (struct mtip_local *)dev->priv; + np_mtip_mac *pmac; + int timeout; + + pmac = ((np_mtip_mac *) dev->base_addr); + + (pmac->mdio0).CONTROL = PHY_CTL_RST_MASK; // Reset the phy + + // set reset and Gig-Speed bits to make sure we have an + // incoming clock on tx side. + // If there is a 10/100 PHY, we will still have a valid clock on + // tx_clk no matter what setting we have here, but on a Gig phy the + // MII clock may be missing. + + pmac->COMMAND_CONFIG = mmac_cc_SW_RESET_mask | mmac_cc_ETH_SPEED_mask; + + // wait for completion with fallback in case there is no PHY or it is + // not connected and hence might not provide any clocks at all. + timeout=0; + while( (pmac->COMMAND_CONFIG & mmac_cc_SW_RESET_mask) != 0 && + timeout < 10000) timeout++; + + pmac->COMMAND_CONFIG = 0; + + // Cleanup pending "forgotten" DMAs + + #if defined (MTIPDMA_AVAIL) + ((np_dma *) (na_dma))->np_dmacontrol = 0; + ((np_dma *) (na_dma))->np_dmastatus = 0; + gMtipDmaState = Mtip_DmaState_Idle; + #endif // MTIPDMA_AVAIL + + // flush RX FIFO + +/* +....?...tbd....?............ +............................*/ + } + + +/*----------------------------------------------------------- + | soft reset the device + | + | Sets the Emac to its normal state. + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_reset( struct net_device* dev ) +{ + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + PRINTK2("%s:mtip_reset\n", dev->name); + + mtip_mac_SwReset( dev ); + + // disable all IRQs + // + pmac->IRQ_CONFIG = 0; + // + #ifdef NS83865PHY + (pmac->mdio0).reg15 = 0; + #else + #ifdef TDK78Q2120PHY + (pmac->mdio0).reg11 = 0; + #else + ...... + #endif + #endif + // + #if defined (MTIPPHYIRQ_AVAIL) + #if defined (na_mii_irq) + (*(volatile unsigned long *) + (((unsigned long *) + ((((char *) + (((int) (mtip_mii_control_port)) + + 0x0008))))))) = + ((unsigned long) (0x0000)); + // Disable phy interrupt pass thru to na_mii_irq + #endif // na_mii_irq + #endif // MTIPPHYIRQ_AVAIL +} + + +/*----------------------------------------------------------- + */ +static void mtip_reset_config(struct net_device *dev) + { + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + mtip_reset( dev ); + + pmac->MAC_0 = + ((unsigned int) + (*((unsigned long *) + (&(((unsigned char *) + (dev->dev_addr))[0]))))); + pmac->MAC_1 = + ((unsigned int) + (*((unsigned short *) + (&(((unsigned char *) + (dev->dev_addr))[4]))))); + + pmac->FRM_LENGTH = MTIP_MAC_MAX_FRAME_SIZE; + pmac->PAUSE_QUANT = 0xff00; + + pmac->RX_SECTION_EMPTY = 0; // Auto tx pause DISabled +// pmac->RX_SECTION_EMPTY = 1900/4; + // If RX FIFO fills to this level, PAUSE frame is sent + + pmac->RX_SECTION_FULL = 0; // Store&forward (must be zero) + pmac->TX_SECTION_EMPTY = (256-16)/4; + + pmac->TX_SECTION_FULL = 0; // NO Early start tx +// pmac->TX_SECTION_FULL = 128/4; // Early start tx: 128 bytes in FIFO + // If TxFifo smaller than outbound packet, early start Tx + // MUST be enabled. + // Slow memory feeding TxFifo must NOT enable early start Tx. + + pmac->RX_ALMOST_EMPTY = 8; // + pmac->RX_ALMOST_FULL = 10; // + pmac->TX_ALMOST_EMPTY = 8; // + pmac->TX_ALMOST_FULL = 16; // Need at least 14 to cope + // with Avalon/DMA latency + return; + } + + +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts ENabled + */ +static void mtip_timeout (struct net_device *dev) +{ +// PRINTK3 + printk + ( +// KERN_WARNING + "%s:mtip_timeout\n", + dev->name); + + /* If we get here, some higher level has decided we are broken. */ + + #if 0 +....FIXME:...preemption sensitive stuff to be accessed with +.... cpu interrupts DISabled... +....If Dma state one of the TX states, must stop the +.... Dma and change to idle state or handle gMtipDmaQ +.... Mtip_DmaQ_RxFifo2Tmp/Mtip_DmaQ_RxFifo2Trash flag(s) +....Ensure Tx "done" interrupt is DISabled +.... +....Empirical observation: we are toast no matter +.... what we do [not]do........... + if(gpMtipTxSkbInProg) + { + #if 0 + printk("%s:mtip_timeout, txSkb 0x%08X freed\n", + dev->name, + ((unsigned int) (gpMtipTxSkbInProg))); + #endif + + dev_kfree_skb_any (gpMtipTxSkbInProg); + gpMtipTxSkbInProg = NULL; + + #if defined (MTIPDMA_AVAIL) + gMtipDmaQ &= (~(Mtip_DmaQ_TxSkb2Tmp)); + #endif + } + + mtip_reset_config( dev ); + mtip_enable( dev ); + mtip_phy_configure(dev); + + mtip_phymac_synch(dev, + 0); // Caller = NOT Phy interrupt handler + + netif_wake_queue(dev); + #endif +} + + +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts ENabled. + */ +static int mtip_hard_start_xmit( struct sk_buff * skb, + struct net_device * dev ) + { + unsigned long flags; + struct mtip_local *lp = (struct mtip_local *)dev->priv; + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + dev->trans_start = jiffies; + netif_stop_queue(dev); + + PRINTK3("%s:mtip_hard_start_xmit\n", dev->name); + + if ( gpMtipTxSkbInProg ) { + lp->stats.tx_aborted_errors++; + printk("mtip_hard_start_xmit:%s, - tx request while busy.\n", + dev->name); + return 1; // Tell caller to retry "later" (if/after someone + // invokes netif_wake_queue(...))... + } + + gMtipTxSkbframelenbyts = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + + if(gMtipTxSkbframelenbyts > MTIP_MAC_MAX_FRAME_SIZE) + { + printk("mtip_hard_start_xmit:%s, oversized %d byte packet.\n", + dev->name, + gMtipTxSkbframelenbyts); + dev_kfree_skb (skb); + netif_wake_queue(dev); + return 0; + } + + gpMtipTxData = skb->data; + + PRINTK3 + ( + "%s:Transmitting %d byte Packet 0x%08X\n", + dev->name, + gMtipTxSkbframelenbyts, + ((unsigned long) (gpMtipTxData))); + #if MTIP_DEBUG > 3 + print_packet( gpMtipTxData, gMtipTxSkbframelenbyts ); + #endif + + gMtipTxSkbFifoNumL32s = ((gMtipTxSkbframelenbyts + 3) >> 2); + + ++(lp->stats.tx_packets); + + local_irq_save(flags); + + gpMtipTxSkbInProg = skb; + + #if defined (MTIPDMA_AVAIL) + + if(gMtipDmaState == Mtip_DmaState_Idle) + { + gMtipDmaState = Mtip_DmaState_TxSkb2Tmp; + local_irq_restore(flags); + + dma_start_TxSkb2Tmp(); + } + else + { + gMtipDmaQ |= Mtip_DmaQ_TxSkb2Tmp; + + local_irq_restore(flags); + } + #else + pmac->TX_CMD_STAT = (gMtipTxSkbframelenbyts | + mmac_tcs_FRAME_COMPLETE_mask); + + outsl(((unsigned long) PIO_port_txFIFO), + gpMtipTxData, + gMtipTxSkbFifoNumL32s ); + // If TxFifo smaller than outbound packet, early start Tx + // must be enabled, else we'll overrun the TxFifo (which + // "could" happen anyway with a "fast" cpu). + // If early start Tx enabled, preemption must be disabled, + // else we might underrun the TxFifo. + + local_irq_restore(flags); + + pmac->IRQ_CONFIG |= mmac_ic_EN_TX_FIFO_EMPTY_mask; + // enable tx done interrupt + #endif // MTIPDMA_AVAIL + + return 0; + } + + +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t mtip_RxInterrupt(int irq, + void *dev_id, + struct pt_regs *regs) + { + unsigned int cmplnstatus; + struct net_device *dev = dev_id; + np_mtip_mac *pmac; + + /* RxInterrupt condition self clears if/when RxFifo accessed. */ + + pmac = ((np_mtip_mac *) dev->base_addr); + + ++gMtipRxints; + + if(!((pmac->IRQ_CONFIG) & (mmac_ic_EN_RX_FRAME_AVAILABLE_mask))) + { + ++gMtipDisabledRxints; + } + + #if defined (MTIPDMA_AVAIL) + + switch (gMtipDmaState) + { + case Mtip_DmaState_RxFifo2Tmp: + case Mtip_DmaState_RxTmp2Skb: + case Mtip_DmaState_RxFifo2Trash: + + ++gMtipRxintsRxdmaBusy; + + return IRQ_HANDLED; + // ...This could be interesting...! + +// case Mtip_DmaState_TxSkb2Tmp: +// case Mtip_DmaState_TxTmp2Fifo: +// case Mtip_DmaState_Idle: +// default: + } + + if (gMtipDmaQ & (Mtip_DmaQ_TxSkb2Tmp | + Mtip_DmaQ_RxFifo2Tmp | + Mtip_DmaQ_RxFifo2Trash)) + { + ++gMtipRxintsRxdmaQued; + + return IRQ_HANDLED; + // ...This could be interesting...! + + } + #endif // MTIPDMA_AVAIL + + cmplnstatus = pmac->RX_CMD_STAT; + + if(!( cmplnstatus & mmac_rcs_VALID_mask )) + { + ++gMtipUnexpRxints; + + PRINTK3 +// printk + ( + "mtip_RxInterrupt:%s, but RxStatus:0x%08X INvalid\n", + dev->name, + cmplnstatus); + + /* ?...RxInterrupt condition...? */ + } + else + { + mtip_NuRxReady(dev, cmplnstatus); + } + + return IRQ_HANDLED; + } + + +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t mtip_TxInterrupt(int irq, + void *dev_id, + struct pt_regs *regs) + { + unsigned long cmdcfg; + struct net_device *dev = dev_id; + struct mtip_local *lp; + int old_txcmdstat; + np_mtip_mac *pmac; + + // Mtip's Tx fifo supposedly could alternatively + // "flow control" the Dma adequately enough to let + // us save this interrupt (if we don't need tx done + // error tallying). + //...Jun2004...NOT the case?...perhaps early tx start + //... plays a part therein...?... + + lp = (struct mtip_local *)dev->priv; + pmac = ((np_mtip_mac *) dev->base_addr); + + ++gMtipTxints; + + if(!((pmac->IRQ_CONFIG) & (mmac_ic_EN_TX_FIFO_EMPTY_mask))) + { + ++gMtipDisabledTxints; + } + + cmdcfg = pmac->COMMAND_CONFIG; + if((cmdcfg & mmac_cc_EXCESS_COL_mask) != 0) + { + ++(lp->stats.collisions); + } + if((cmdcfg & mmac_cc_LATE_COL_mask) != 0) + { + lp->stats.tx_window_errors++; + // ifconfig displays as "carrier" errors. + + PRINTK3 +// printk + ( +// KERN_NOTICE + "mtip_TxInterrupt:%s, Late collision on last xmit.\n", + dev->name); + } + + old_txcmdstat = pmac->TX_CMD_STAT; + + if(gpMtipTxSkbInProg) + { + if(!(old_txcmdstat & mmac_tcs_FRAME_COMPLETE_mask)) + { + dev_kfree_skb_any (gpMtipTxSkbInProg); + gpMtipTxSkbInProg = NULL; + } + else + { + ++gMtipTxintsIncomplete; + + return IRQ_HANDLED; + // ...This could be interesting...! + } + } + else + { + ++gMtipUnexpTxints; + } + + pmac->IRQ_CONFIG &= (~(mmac_ic_EN_TX_FIFO_EMPTY_mask)); + + netif_wake_queue(dev); + + return IRQ_HANDLED; + } + + +#if defined (MTIPPHYIRQ_AVAIL) +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t mtip_PhyInterrupt(int irq, + void *dev_id, + struct pt_regs *regs) + { + struct net_device *dev = dev_id; + np_mtip_mac *pmac; + #ifdef NS83865PHY + unsigned int nsIntstsReg20; + unsigned int nsIntieReg21; + unsigned int nsLnkstsReg17; + #else + #ifdef TDK78Q2120PHY + unsigned int tdkDiagReg18; + unsigned int tdkintCtlStsReg17; + #endif + #endif + + pmac = ((np_mtip_mac *) dev->base_addr); + + #if defined(ANNOUNCEPHY) + printk + ( + "mtip_PhyInterrupt:%s\n", + dev->name); + #endif + + #ifdef NS83865PHY + nsIntstsReg20 = (pmac->mdio0).reg14; + nsIntieReg21 = (pmac->mdio0).reg15; + nsLnkstsReg17 = (pmac->mdio0).reg11; + + #if 0 + PRINTNS83PHYREGS(pmac, + nsIntstsReg20, + nsIntieReg21, + nsLnkstsReg17); + #endif + + (pmac->mdio0).reg17 = nsIntstsReg20; + // Ack (all) interrupt condition(s) + #else + #ifdef TDK78Q2120PHY + tdkintCtlStsReg17 = (pmac->mdio0).reg11; + // Read TDK 78Q2120 interrupt control/status register + // Also acks the interrupt condition(s) + + tdkDiagReg18 = (pmac->mdio0).reg12; + // Read TDK 78Q2120 diagnostic register + // Also clears auto-negotiation failed bit + + #if 0 + PRINTTDKPHYREGS(pmac, tdkintCtlStsReg17, tdkDiagReg18); + #endif + #else + ...... + #endif + #endif + + mtip_phymac_synch((struct net_device *) dev_id, + 1); // Caller = Phy interrupt handler + + return IRQ_HANDLED; + } +#endif // MTIPPHYIRQ_AVAIL + + +/*----------------------------------------------------------- + | Driver entry point (eg: ifconfig ethX up). + | (eg: ifattach ...) + | + | Open and Initialize the board + | + | Set up everything, reset the card, etc .. + | + | Entry condition: Cpu interrupts ENabled. + */ +static int mtip_open(struct net_device *dev) +{ + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + PRINTK2("%s:mtip_open\n", dev->name); + + memset(dev->priv, 0, sizeof(struct mtip_local)); + + + #ifdef CONFIG_SYSCTL + // Set default parameters (files) +/* +....tbd............. +.....................*/ + #endif + + mtip_reset_config( dev ); + mtip_enable( dev ); + mtip_phy_configure(dev); + + mtip_phymac_synch(dev, + 0); // Caller = NOT Phy interrupt handler + +#ifdef CONFIG_SYSCTL + mtip_sysctl_register(dev); +#endif /* CONFIG_SYSCTL */ + + netif_start_queue(dev); + + return 0; +} + + +/*----------------------------------------------------------- + | close down the Emac + | + | put the device in an inactive state + | +*/ +static void mtip_shutdown( struct net_device *dev ) +{ + PRINTK2("%s:mtip_shutdown\n", dev->name); + +/* +....tbd............. +...........................*/ +} + + +/*----------------------------------------------------------- + | Driver entry point (eg: ifconfig ethX down). + | + | Clean up everything from the open routine +*/ +static int mtip_close(struct net_device *dev) +{ + PRINTK2("%s:mtip_close\n", dev->name); + + netif_stop_queue(dev); + + if(gpMtipTxSkbInProg) + { + dev_kfree_skb_any (gpMtipTxSkbInProg); + gpMtipTxSkbInProg = NULL; + + #if defined (MTIPDMA_AVAIL) + gMtipDmaQ &= (~(Mtip_DmaQ_TxSkb2Tmp)); + #endif + } + + #if defined (MTIPDMA_AVAIL) + gMtipDmaQ = 0; + gMtipDmaState = Mtip_DmaState_Idle; + #endif // MTIPDMA_AVAIL + +#ifdef CONFIG_SYSCTL + mtip_sysctl_unregister(dev); +#endif /* CONFIG_SYSCTL */ + + /* clear everything */ + mtip_shutdown( dev ); + + /* Update the statistics here. */ + + return 0; +} + + +/*----------------------------------------------------------- + | Driver entry point (re unregister_netdev()). + | + | Cleaning up before driver finally unregistered and discarded. + | + | Input parameters: + | dev, pointer to the device structure + | + | Output: + | None. + | + --------------------------------------------------------------------------- +*/ +void mtip_destructor(struct net_device *dev) +{ + PRINTK2("%s:mtip_destructor\n", dev->name); +} + + +/*----------------------------------------------------------- + | Driver entry point. + | + | Get the current statistics. + | + | Allows proc file system to query the driver's statistics. + | + | May be called with the card open or closed. + | + | Entry condition: Cpu interrupts ENabled. +*/ +static struct net_device_stats* mtip_query_statistics(struct net_device *dev) + { + struct mtip_local *lp = (struct mtip_local *)dev->priv; + + PRINTK2("%s:mtip_query_statistics\n", dev->name); + + return &lp->stats; + } + + +/*----------------------------------------------------------- + | Clear the multicast table to disable multicast reception. + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_mac_clearMulticast(struct net_device *dev) + { + int i; + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + for(i=0; i < 64; i++ ) + { + (pmac->hashtable)[i] = 0; + } + } + + +/*----------------------------------------------------------- + | Fill the multicast table to enable reception of all multicast frames. + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_mac_promiscuousMulticast(struct net_device *dev) + { + int i; + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + for(i=0; i < 64; i++ ) + { + (pmac->hashtable)[i] = 1; + } + } + + +/*----------------------------------------------------------- + | Reprogram multicast mac addresses into hardware multicast table + | + | Caller has already cleared existing hash entries as appropriate + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_setmulticast( struct net_device *dev, + int count, + struct dev_mc_list *addrs ) + { + int a; + int bit; + int bitidx; + int hash; + int i; + char ch; + struct dev_mc_list *cur_addr; + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + PRINTK2 + ( + "mtip_setmulticast:%s\n", + dev->name); + + cur_addr = addrs; + + for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) + { + /* do we have a pointer here? */ + if ( !cur_addr ) + break; + + /* make sure this is a multicast address */ + if ( !( *cur_addr->dmi_addr & 1 ) ) + continue; + + hash = 0; // the hash value + + for(a=5; a >= 0; a--) + { + // loop through all 6 bytes of this mac address + + bit = 0; // the bit calculated from the byte + ch = (cur_addr->dmi_addr)[a]; + + for(bitidx=0;bitidx < 8;bitidx++) + { + bit ^= (int)((ch >> bitidx) & 0x01); + } + + hash = (hash << 1) | bit; + } + + #if (MTIP_DEBUG > 2 ) +// printk(" "); + printk("mtip_setmulticast: "); + for(a=0; a < 6; a++) + { + ch = (cur_addr->dmi_addr)[a]; + + printk(" %02X",ch); + } + printk(" hash(%d)\n",hash); + #endif + + (pmac->hashtable)[ hash ] = 1; + } + } + + +/*----------------------------------------------------------- + | Driver entry point. + | + | This routine will, depending on the values passed to it, + | either make it accept multicast packets, go into + | promiscuous mode ( for TCPDUMP and cousins ) or accept + | a select set of multicast packets + | + | Entry condition: Cpu interrupts ENabled. +*/ +static void mtip_set_multicast_list(struct net_device *dev) + { + np_mtip_mac *pmac; + + pmac = ((np_mtip_mac *) dev->base_addr); + + PRINTK2 + ( + "%s:mtip_set_multicast_list\n", + dev->name); + + if ( dev->flags & IFF_PROMISC ) + { + PRINTK2 +// printk + ( + "%s:mtip_set_multicast_list:RCR_PRMS\n", dev->name); + + mtip_mac_setPromiscuous(pmac); + } + else + { + PRINTK2 +// printk + ( + "%s:mtip_set_multicast_list:~RCR_PRMS\n", dev->name); + + mtip_mac_clearPromiscuous(pmac); + } + + if (dev->flags & IFF_ALLMULTI) + { + PRINTK2 +// printk + ( + "%s:mtip_set_multicast_list:RCR_ALMUL\n", dev->name); + + mtip_mac_promiscuousMulticast(dev); + } + else + { + PRINTK2 + ( + "%s:mtip_set_multicast_list:~RCR_ALMUL\n", dev->name); + + mtip_mac_clearMulticast(dev); // Clear any existing hash entries + + if(dev->mc_count) + { + mtip_setmulticast( dev, + dev->mc_count, + dev->mc_list ); + } + } + } + + +/*----------------------------------------------------------- + | Entry condition: Cpu interrupts ENabled + | (in SPITE of claims disabled...). +*/ +static int __init mtip_probe(struct net_device *dev, unsigned int ioaddr ) +{ + int i; + np_mtip_mac *pmac; + int retval; + static unsigned version_printed = 0; + + + pmac = ((np_mtip_mac *) ioaddr); + + PRINTK2("%s:mtip_probe\n", dev->name); + + SET_MODULE_OWNER (dev); + +#if 1 + #ifdef CONFIG_EXCALIBUR + printk("mtip_probe:%s, %d Khz Nios (%s) (%s)\n", + dev->name, + nasys_clock_freq_1000, + PHYTYPE, + IOTYPE); + #endif +#endif + + /* Grab the region so that no one else tries to probe our ioports. */ + if (!request_region(ioaddr, + MTIP1000_IO_EXTENT, + dev->name)) return -EBUSY; + + if (version_printed++ == 0) printk("%s", version); + + dev->base_addr = ioaddr; + + #ifdef NS83865PHY + { + int oldmdioaddr0; + int phyaddr = -1; + + // Empirical observation: expect NS83865PHY's phy address = 2 + + oldmdioaddr0 = pmac->MDIO_ADDR0; + + for (i = 0; i <= 31; i++) + { + pmac->MDIO_ADDR0 = i; + + if(((pmac->mdio0).PHY_ID1) == 0x2000) + { + phyaddr = i; + + break; + } + } + + if(phyaddr >= 0) + { + pmac->MDIO_ADDR0 = phyaddr; + } + else + { + pmac->MDIO_ADDR0 = oldmdioaddr0; + + printk("mtip_probe:%s, (%s) phy not found" + ", defaulting to addr:0x%02X\n", + dev->name, + PHYTYPE, + pmac->MDIO_ADDR0); + } + } + #else + #ifdef TDK78Q2120PHY + // TDK78Q2120PHY's respond to the "broadcast" phy address 0, + // so leave pmac->MDIO_ADDR0 at its default value 0 + #else + ...... + #endif + #endif // NS83865PHY + + mtip_reset( dev ); + + printk("mtip_probe:%s, REV=0x%08x, (%s) Phyaddr:0x%02X\n", + dev->name, + pmac->REV, + PHYTYPE, + pmac->MDIO_ADDR0); + + #if 0 + #ifdef NS83865PHY + PRINTNS83PHYREGS(pmac, + ((unsigned int) ((pmac->mdio0).reg14)), + ((unsigned int) ((pmac->mdio0).reg15)), + ((unsigned int) ((pmac->mdio0).reg11))); + #else + #ifdef TDK78Q2120PHY + PRINTTDKPHYREGS(pmac, + ((unsigned int) ((pmac->mdio0).reg11)), + ((unsigned int) ((pmac->mdio0).reg12))); + #else + ...... + #endif + #endif + #endif + +#ifdef CONFIG_EXCALIBUR + { + extern unsigned char *excalibur_enet_hwaddr; + + memcpy(dev->dev_addr, excalibur_enet_hwaddr, 6); + } +#else + ......... +#endif + + /* + . Print the Ethernet address + */ + printk(" ADDR: "); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i] ); + printk("%2.2x \n", dev->dev_addr[5] ); + + /* set the private data to zero by default */ + memset(dev->priv, 0, sizeof(struct mtip_local)); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + /* Grab the RxIRQ */ + retval = request_irq(dev->irq, + mtip_RxInterrupt, + 0, + dev->name, + dev); + if (retval) { + printk("mtip_probe:%s unable to hook RxIRQ %d (retval=%d).\n", + dev->name, + dev->irq, + retval); + + goto frepriv_err_out; + } + + retval = request_irq(na_mtip_mac_txFIFO_irq, + mtip_TxInterrupt, + 0, + dev->name, + dev); + if (retval) { + printk("mtip_probe:%s unable to hook TxIRQ %d (retval=%d).\n", + dev->name, + na_mtip_mac_txFIFO_irq, + retval); + + goto freRxIrq_err_out; + } + + #if defined (MTIPPHYIRQ_AVAIL) + /* Grab the PhyIRQ */ + retval = request_irq(na_mii_irq_irq, + mtip_PhyInterrupt, + 0, + dev->name, + dev); + if (retval) + { + printk("mtip_probe:%s unable to hook PhyIRQ %d (retval=%d).\n", + dev->name, + na_mii_irq_irq, + retval); + + goto freTxIrq_err_out; + } + #endif // MTIPPHYIRQ_AVAIL + + gMtipDisabledRxints = 0; + gMtipDisabledTxints = 0; + gMtipDmaints = 0; + gMtipDmaintsBusy = 0; + gMtipDmaintsBusyDone = 0; + gMtipDmaintsNoDone = 0; + gMtipRxints = 0; + gMtipRxintsRxdmaBusy = 0; + gMtipRxintsRxdmaQued = 0; + gMtipRxNoints = 0; + gMtipTxints = 0; + gMtipTxintsIncomplete = 0; + gMtipUnexpDmaints = 0; + gMtipUnexpRxints = 0; + gMtipUnexpTxints = 0; + gpMtipTxSkbInProg = NULL; + + #if defined (MTIPDMA_AVAIL) + gMtipDmaQ = 0; + gMtipDmaState = Mtip_DmaState_Idle; + + /* Grab the DmaIRQ */ + retval = request_irq(na_dma_irq, + mtip_DmaInterrupt, + 0, + dev->name, + dev); + if (retval) { + printk("mtip_probe:%s unable to hook DmaIRQ %d (retval=%d).\n", + dev->name, + na_dma_irq, + retval); + + goto frePhyIrq_err_out; + } + #endif // MTIPDMA_AVAIL + +// see mtip_phymac_synch for full/half duplex coordination + + dev->open = mtip_open; + dev->stop = mtip_close; + dev->hard_start_xmit = mtip_hard_start_xmit; + dev->tx_timeout = mtip_timeout; + dev->get_stats = mtip_query_statistics; + #ifdef HAVE_MULTICAST + dev->set_multicast_list = &mtip_set_multicast_list; + #endif + + return 0; + + #if defined (MTIPPHYIRQ_AVAIL) + #if defined (MTIPDMA_AVAIL) +frePhyIrq_err_out: + #endif // MTIPDMA_AVAIL + + free_irq(na_mii_irq_irq, dev); + +freTxIrq_err_out: + #endif // MTIPPHYIRQ_AVAIL + + free_irq(na_mtip_mac_txFIFO_irq, + dev); + +freRxIrq_err_out: + + free_irq(na_mtip_mac_rxFIFO_irq, + dev); + +frepriv_err_out: + + kfree (dev->priv); + dev->priv = NULL; + +//err_out: + release_region (ioaddr, MTIP1000_IO_EXTENT); + return retval; +} + + +/*----------------------------------------------------------- + | Driver entry point (called by ethif_probe2()). + | + | Return: 0 success. + | + | Entry condition: Cpu interrupts ENabled + | (in SPITE of claims disabled...). +*/ +struct net_device * __init mtip1000_init(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct mtip_local)); + int err = 0; + int i; + + if (!dev) return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + PRINTK2("%s:mtip1000_init\n", dev->name); + + for (i = 0; mtip_portlist[i]; i++) { + dev->irq = mtip_irqlist[i]; + + if (mtip_probe(dev, mtip_portlist[i]) == 0) break; + } + + if (!mtip_portlist[i]) err = -ENODEV; + if (err) goto out; + + err = register_netdev(dev); + if (err) goto out; + return dev; +out: + free_netdev(dev); + // printk(KERN_WARNING "mtip1000: no emac unit %d detected.\n",unit); + return ERR_PTR(err); +} diff --git a/drivers/net/mtip1000.h b/drivers/net/mtip1000.h new file mode 100644 index 00000000..18d784d5 --- /dev/null +++ b/drivers/net/mtip1000.h @@ -0,0 +1,408 @@ +/*---------------------------------------------------------------------- + . mtip1000.c + . + . Driver: MoreThanIP 10/100/1000Mbps Emac IP + . + . Copyright ... + to + be + completed + ... + . + . Sources: + . o MoreThanIP 10/100/1000Mbps Reference Guide V3.2 - May 2003 + . o MoreThanIP Altera Plugs sources + . o Smc9111 uClinux port(s) + . + . History: + . o Apr2004 DGT Microtronix Datacom + . + -----------------------------------------------------------------------*/ + +#ifndef _MTIP1000_H_ + #define _MTIP1000_H_ + +/*----------------------------------------------------------------------*/ + +#ifndef na_mtip_mac_control_port + #if defined (na_mip_mac_control_port) + #define na_mtip_mac_control_port na_mip_mac_control_port + #endif +#endif +#ifndef na_mtip_mac_rxFIFO + #if defined (na_mip_mac_rxFIFO) + #define na_mtip_mac_rxFIFO na_mip_mac_rxFIFO + #endif +#endif +#ifndef na_mtip_mac_rxFIFO_irq + #if defined (na_mip_mac_rxFIFO_irq) + #define na_mtip_mac_rxFIFO_irq na_mip_mac_rxFIFO_irq + #endif +#endif +#ifndef na_mtip_mac_txFIFO + #if defined (na_mip_mac_txFIFO) + #define na_mtip_mac_txFIFO na_mip_mac_txFIFO + #endif +#endif +#ifndef na_mtip_mac_txFIFO_irq + #if defined (na_mip_mac_txFIFO_irq) + #define na_mtip_mac_txFIFO_irq na_mip_mac_txFIFO_irq + #endif +#endif + +/*----------------------------------------------------------------------*/ + +// Number of bytes the largest frame can have. +// For receive, should be at least the MAC's FRAME_LENGTH +// programmed value + 8. +#define MTIP_MAC_MAX_FRAME_SIZE 1524 +// +// Receive buffer must be at least 'maximum possible frame size'+16. +#define MTIP_MI_XBUF_BYTS 24 +#define MTIP_SKB_XBUF_BYTS MTIP_MI_XBUF_BYTS + +// MDIO registers within MAC register Space +// memory mapped access +// +typedef volatile struct +{ + unsigned int CONTROL; + unsigned int STATUS; + unsigned int PHY_ID1; + unsigned int PHY_ID2; + unsigned int ADV; + unsigned int REMADV; + + unsigned int reg6; + unsigned int reg7; + unsigned int reg8; + unsigned int reg9; + unsigned int rega; + unsigned int regb; + unsigned int regc; + unsigned int regd; + unsigned int rege; + unsigned int regf; + unsigned int reg10; + unsigned int reg11; + unsigned int reg12; + unsigned int reg13; + unsigned int reg14; + unsigned int reg15; + unsigned int reg16; + unsigned int reg17; + unsigned int reg18; + unsigned int reg19; + unsigned int reg1a; + unsigned int reg1b; + unsigned int reg1c; + unsigned int reg1d; + unsigned int reg1e; + unsigned int reg1f; + +} np_mtip_mdio; + +// MAC Registers - 32 Bit +// +typedef volatile struct +{ + unsigned int REV; + unsigned int SCRATCH; + unsigned int COMMAND_CONFIG; + unsigned int MAC_0; + unsigned int MAC_1; + unsigned int FRM_LENGTH; + unsigned int PAUSE_QUANT; + unsigned int RX_SECTION_EMPTY; + unsigned int RX_SECTION_FULL; + unsigned int TX_SECTION_EMPTY; + unsigned int TX_SECTION_FULL; + unsigned int RX_ALMOST_EMPTY; + unsigned int RX_ALMOST_FULL; + unsigned int TX_ALMOST_EMPTY; + unsigned int TX_ALMOST_FULL; + unsigned int MDIO_ADDR0; + unsigned int MDIO_ADDR1; + + unsigned int AUTONEG_CNTL; + // only if 100/1000 BaseX PCS, reserved otherwise + + unsigned int AN_ABILITY_INT; + unsigned int LP_ABILITY_INT; + unsigned int LINK_TIMER_INT; + + unsigned int reservedx54; + unsigned int reservedx58; + unsigned int reservedx5C; + + unsigned int aMACID_1; + unsigned int aMACID_2; + unsigned int aFramesTransmittedOK; + unsigned int aFramesReceivedOK; + unsigned int aFramesCheckSequenceErrors; + unsigned int aAlignmentErrors; + unsigned int aOctetsTransmittedOK; + unsigned int aOctetsReceivedOK; + unsigned int aTxPAUSEMACCtrlFrames; + unsigned int aRxPAUSEMACCtrlFrames; + unsigned int ifInErrors; + unsigned int ifOutErrors; + unsigned int ifInUcastPkts; + unsigned int ifInBroadcastPkts; + unsigned int ifInMulticastPkts; + unsigned int ifOutDiscards; + unsigned int ifOutUcastPkts; + unsigned int ifOutBroadcastPkts; + unsigned int ifOutMulticastPkts; + unsigned int etherStatsDropEvent; + unsigned int etherStatsOctets; + unsigned int etherStatsPkts; + unsigned int etherStatsUndersizePkts; + unsigned int etherStatsOversizePkts; + unsigned int etherStatsPkts64Octets; + unsigned int etherStatsPkts65to127Octets; + unsigned int etherStatsPkts128to255Octets; + unsigned int etherStatsPkts256to511Octets; + unsigned int etherStatsPkts512to1023Octets; + unsigned int etherStatsPkts1024to1518Octets; + + unsigned int reservedxD8; + unsigned int reservedxDC; + + unsigned int AVL_STATUS; + unsigned int IRQ_CONFIG; + int TX_CMD_STAT; + int RX_CMD_STAT; + + unsigned int reservedxF0; + unsigned int reservedxF4; + unsigned int reservedxF8; + unsigned int reservedxFC; + + unsigned int hashtable[64]; + + np_mtip_mdio mdio0; + np_mtip_mdio mdio1; + +} np_mtip_mac; + + +// Base-Structure for all library functions + +typedef struct { + + np_mtip_mac *mac; +#ifdef nasys_dma_0 + np_dma *dma; + np_dma *dma_rx; +#else + int *dma; + int *dma_rx; +#endif + volatile unsigned int *rxFIFO; + volatile unsigned int *txFIFO; + + unsigned int cfgflags; + // flags or'ed during initialization of COMMAND_CONFIG + + int *rxbuf; // receive buffer to use + +} mtip_mac_trans_info; + +// COMMAND_CONFIG Register Bits +// +enum +{ + mmac_cc_TX_ENA_bit = 0, + mmac_cc_RX_ENA_bit = 1, + mmac_cc_XOFF_GEN_bit = 2, + mmac_cc_ETH_SPEED_bit = 3, + mmac_cc_PROMIS_EN_bit = 4, + mmac_cc_PAD_EN_bit = 5, + mmac_cc_CRC_FWD_bit = 6, + mmac_cc_PAUSE_FWD_bit = 7, + mmac_cc_PAUSE_IGNORE_bit = 8, + mmac_cc_TX_ADDR__INS_bit = 9, + mmac_cc_HD_ENA_bit = 10, + mmac_cc_EXCESS_COL_bit = 11, + mmac_cc_LATE_COL_bit = 12, + mmac_cc_SW_RESET_bit = 13, +//;dgt2; mmac_cc_MHASH_SEL_bit = 13, + mmac_cc_MHASH_SEL_bit = 14, //;dgt2; + mmac_cc_LOOPBACK_bit = 15, + mmac_cc_TX_ADDR_SEL_bit = 16, // bits 18:16 = address select + mmac_cc_MAGIC_ENA_bit = 19, + mmac_cc_SLEEP_ENA_bit = 20, + + mmac_cc_TX_ENA_mask = (1 << 0), // enable TX + mmac_cc_RX_ENA_mask = (1 << 1), // enable RX + mmac_cc_XOFF_GEN_mask = (1 << 2), // generate Pause frame with Quanta + mmac_cc_ETH_SPEED_mask = (1 << 3), // Select Gigabit + mmac_cc_PROMIS_EN_mask = (1 << 4), // enable Promiscuous mode + mmac_cc_PAD_EN_mask = (1 << 5), // enable padding remove on RX + mmac_cc_CRC_FWD_mask = (1 << 6), // forward CRC to application on RX (as opposed to stripping it off) + mmac_cc_PAUSE_FWD_mask = (1 << 7), // forward Pause frames to application + mmac_cc_PAUSE_IGNORE_mask = (1 << 8), // ignore Pause frames + mmac_cc_TX_ADDR_INS_mask = (1 << 9), // MAC overwrites bytes 6 to 12 of frame with address on all transmitted frames + mmac_cc_HD_ENA_mask = (1 << 10),// enable half-duplex operation + mmac_cc_EXCESS_COL_mask = (1 << 11),// indicator + mmac_cc_LATE_COL_mask = (1 << 12),// indicator + mmac_cc_SW_RESET_mask = (1 << 13),// issue register and counter reset + mmac_cc_MHASH_SEL_mask = (1 << 14),// select multicast hash method + mmac_cc_LOOPBACK_mask = (1 << 15),// enable GMII loopback + mmac_cc_MAGIC_ENA_mask = (1 << 19),// enable magic packet detect + mmac_cc_SLEEP_ENA_mask = (1 << 20) // enter sleep mode +}; + +// AVL_STATUS Register Bits + +enum +{ + mmac_as_RX_FRAME_AVAILABLE_mask = (1 << 0), + mmac_as_TX_FIFO_EMPTY_mask = (1 << 1), + mmac_as_TX_FIFO_SEPTY_mask = (1 << 2) +}; + + +// IRQ_CONFIG Register Bits + +enum +{ + mmac_ic_EN_RX_FRAME_AVAILABLE_mask = (1 << 0), // rx frame available (status FIFO) + mmac_ic_EN_TX_FIFO_EMPTY_mask = (1 << 1), // tx section empty + mmac_ic_EN_RX_MAGIC_FRAME_mask = (1 << 2), // magic frame received interrupt when in sleep mode + mmac_ic_OR_WRITE = (1 << 30), // if set, write data is OR'ed with current register bits + mmac_ic_AND_WRITE = (1 << 31) // if set, write data is AND'ed with current register bits +}; + + +// TX_CMD_STAT Register bits +// +enum{ + mmac_tcs_LENGTH_mask = 0x3fff, // length portion + mmac_tcs_FRAME_COMPLETE_mask = (1 << 31), // negative as long as frame is not complete + mmac_tcs_SET_ERROR_mask = (1 << 16), + mmac_tcs_OMIT_CRC_mask = (1 << 17) +}; + + +// RX_CMD_STAT Register bits +// +enum{ + mmac_rcs_FRAME_LENGTH_mask = 0x0000ffff, + mmac_rcs_ERROR_mask = (1 << 16), + //mmac_rcs_FIFO_OVERFLOW_mask = (1 << xx), //;dgt2; ??? + mmac_rcs_VLAN_mask = (1 << 17), + mmac_rcs_MCAST_mask = (1 << 18), + mmac_rcs_BCAST_mask = (1 << 19), + mmac_rcs_UNICAST_mask = (1 << 20), //;dgt2; 20 or 23 ?... + mmac_rcs_READ_CMD_mask = (1 << 24), + mmac_rcs_VALID_mask = (1 << 31) +}; + + +/** extracts AVL_STATUS' VALID bit to detect if there is a frame in the RX fifo. */ +// +//;dgt2;nix; +//;dgt2;-only if; +//;dgt2; Avl_Status; +//;dgt2; says frame; +//;dgt2; available...?...; +//;dgt2; #define mtip_mac_isFrameAvail( pmtip_mac ) ( pmtip_mac->RX_CMD_STAT & mmac_rcs_VALID_mask ) + +/** extracts length of frame currently available in the FIFO. */ +// +#define mtip_mac_getFrameLength( pmtip_mac) ( pmtip_mac->RX_CMD_STAT & mmac_rcs_FRAME_LENGTH_mask ) + +/** set promiscous bit. */ +// +#define mtip_mac_setPromiscuous( pmtip_mac) ( pmtip_mac->COMMAND_CONFIG |= mmac_cc_PROMIS_EN_mask ) + +/** clear promiscuous bit. */ +// +#define mtip_mac_clearPromiscuous(pmtip_mac) ( pmtip_mac->COMMAND_CONFIG &= ~mmac_cc_PROMIS_EN_mask ) + + +/** switch MAC into MII (10/100) mode. */ +// +#define mtip_mac_setMIImode( pmtip_mac ) ( pmtip_mac->COMMAND_CONFIG &= ~mmac_cc_ETH_SPEED_mask ) + +/** switch MAC into GMII (Gigabit) mode. */ +#define mtip_mac_setGMIImode( pmtip_mac ) ( pmtip_mac->COMMAND_CONFIG |= mmac_cc_ETH_SPEED_mask ) + + +// PCS -------------- + +/** PCS Control Register Bits. IEEE 802.3 Clause 22.2.4.1 + */ +enum { + PCS_CTL_speed1 = 1<<6, // speed select + PCS_CTL_speed0 = 1<<13, + PCS_CTL_fullduplex = 1<<8, // fullduplex mode select + PCS_CTL_an_restart = 1<<9, // Autonegotiation restart command + PCS_CTL_isolate = 1<<10, // isolate command + PCS_CTL_powerdown = 1<<11, // powerdown command + PCS_CTL_an_enable = 1<<12, // Autonegotiation enable + PCS_CTL_rx_slpbk = 1<<14, // Serial Loopback enable + PCS_CTL_sw_reset = 1<<15 // perform soft reset + + }; + +/** PCS Status Register Bits. IEEE 801.2 Clause 22.2.4.2 + */ +enum { + PCS_ST_has_extcap = 1<<0, // PHY has extended capabilities registers + PCS_ST_rx_sync = 1<<2, // RX is in sync (8B/10B codes o.k.) + PCS_ST_an_ability = 1<<3, // PHY supports autonegotiation + PCS_ST_rem_fault = 1<<4, // Autonegotiation completed + PCS_ST_an_done = 1<<5 + + }; + +/** Autonegotiation Capabilities Register Bits. IEEE 802.3 Clause 37.2.1 */ + +enum { + ANCAP_NEXTPAGE = 1 << 15, + ANCAP_ACK = 1 << 14, + ANCAP_RF2 = 1 << 13, + ANCAP_RF1 = 1 << 12, + ANCAP_PS2 = 1 << 8, + ANCAP_PS1 = 1 << 7, + ANCAP_HD = 1 << 6, + ANCAP_FD = 1 << 5 + // all others are reserved + }; + +/*----------------------------------------------------------------------*/ + + #define MTIP1000_IO_EXTENT (sizeof(np_mtip_mac)) + +/*----------------------------------------------------------------------*/ + + #ifdef CONFIG_SYSCTL + + /* + * Declarations for the sysctl interface, which allows users to + * control the finer aspects of the Emac. Since the + * module registers its sysctl table dynamically, the sysctl path + * for module FOO is /proc/sys/dev/ethX/FOO + */ + #define CTL_MTIP1000 (CTL_BUS+1389) + // arbitrary and hopefully unused + + enum + { + CTL_MTIP_INFO = 1, // Sysctl files information + CTL_MTIP_SWVER, // Driver Software Version Info + //...fixme... + #ifdef MTIP_DEBUG + // Register access for debugging + //...fixme... + #endif + // --------------------------------------------------- + CTL_MTIP_LAST_ENTRY // Add new entries above the line + }; + + #endif // CONFIG_SYSCTL + +#endif /* _MTIP1000_H_ */ diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 787aa422..d5ae85d7 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -30,6 +30,7 @@ Richard Guenther : Added support for ISAPnP cards Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. Hayato Fujiwara : Add m32r support. + Greg Ungerer : added some coldfire addressing code. */ @@ -61,7 +62,22 @@ static const char version2[] = #include "8390.h" +#ifdef CONFIG_COLDFIRE +#define COLDFIRE_NE2000_FUNCS +#include +#include +#include +unsigned char ne_defethaddr[] = { 0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01 }; +#endif /* CONFIG_COLDFIRE */ +#if defined(CONFIG_M5307) && defined(CONFIG_NETtel) +static unsigned int ne_portlist[] = { NE2000_ADDR0, NE2000_ADDR1, 0 }; +static unsigned int ne_irqlist[] = { NE2000_IRQ_VECTOR0,NE2000_IRQ_VECTOR1,0 }; +#endif + #define DRV_NAME "ne" +#if defined(CONFIG_CPU_H8300H) +#include +#endif /* Some defines that people can play with if so inclined. */ @@ -189,6 +205,31 @@ static int __init do_ne_probe(struct net_device *dev) int orig_irq = dev->irq; #endif +#if defined (CONFIG_NETtel) && defined (CONFIG_M5307) + static int index = 0; + if (!ne_portlist[index]) + return -ENXIO; + dev->base_addr = base_addr = ne_portlist[index]; + dev->irq = ne_irqlist[index++]; +#elif defined(CONFIG_COLDFIRE) + static int once = 0; + + if (once) + return -ENXIO; + if (base_addr == 0) { + dev->base_addr = base_addr = NE2000_ADDR; + dev->irq = NE2000_IRQ_VECTOR; + once++; + } +#elif defined(CONFIG_CPU_H8300H) + static int once = 0; + if (once) + return -ENXIO; + dev->base_addr = base_addr = NE2000_ADDR; + dev->irq = NE2000_IRQ_VECTOR; + once++; +#endif + SET_MODULE_OWNER(dev); /* First check any supplied i/o locations. User knows best. */ @@ -222,7 +263,6 @@ struct net_device * __init ne_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); @@ -296,9 +336,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) int reg0, ret; static unsigned version_printed; - if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) +#if !defined(CONFIG_COLDFIRE) && !defined(CONFIG_CPU_H8300H) + if (!request_region(ioaddr, NE_IO_EXTENT, dev->name)) return -EBUSY; - +#endif reg0 = inb_p(ioaddr); if (reg0 == 0xFF) { ret = -ENODEV; @@ -390,10 +431,92 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) wordlength = 1; } +#if defined(CONFIG_M5307) || defined(CONFIG_M5407) + { + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + for(i = 0; i < 6; i++) + { + SA_prom[i] = inb(ioaddr + i + 1); + } + SA_prom[14] = SA_prom[15] = 0x57; + } +#endif /* CONFIG_M5307 || CONFIG_M5407 */ +#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) + { + unsigned char *ep; + static int nr = 0; + ep = (unsigned char *) (0xf0006000 + (nr++ * 6)); + /* + * MAC address should be in FLASH, check that it is valid. + * If good use it, otherwise use the default. + */ + if (((ep[0] == 0xff) && (ep[1] == 0xff) && (ep[2] == 0xff) && + (ep[3] == 0xff) && (ep[4] == 0xff) && (ep[5] == 0xff)) || + ((ep[0] == 0) && (ep[1] == 0) && (ep[2] == 0) && + (ep[3] == 0) && (ep[4] == 0) && (ep[5] == 0))) { + ep = (unsigned char *) &ne_defethaddr[0]; + ne_defethaddr[5]++; + } + + for(i = 0; i < 6; i++) + SA_prom[i] = ep[i]; + SA_prom[14] = SA_prom[15] = 0x57; + +#if defined(CONFIG_M5206e) && defined(CONFIG_NETtel) + wordlength = 1; + + /* We must set the 8390 for 8bit mode. */ + outb_p(0x48, ioaddr + EN0_DCFG); +#endif + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + } +#elif defined(CONFIG_CFV240) + { + unsigned char *ep = (unsigned char *) 0xffc0406b; + /* + * MAC address should be in FLASH, check that it is valid. + * If good use it, otherwise use the default. + */ + if (((ep[0] == 0xff) && (ep[1] == 0xff) && (ep[2] == 0xff) && + (ep[3] == 0xff) && (ep[4] == 0xff) && (ep[5] == 0xff)) || + ((ep[0] == 0) && (ep[1] == 0) && (ep[2] == 0) && + (ep[3] == 0) && (ep[4] == 0) && (ep[5] == 0))) { + ep = (unsigned char *) &ne_defethaddr[0]; + ne_defethaddr[5]++; + } + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + for(i = 0; i < 6; i++) + SA_prom[i] = ep[i]; + SA_prom[14] = SA_prom[15] = 0x57; + } +#elif defined(CONFIG_M5206e) + { + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + for(i = 0; i < 6; i++) + { + SA_prom[i] = inb(ioaddr + i + 1); + } + SA_prom[14] = SA_prom[15] = 0x57; + if(!SA_prom[0] && !SA_prom[1] && !SA_prom[2]) { + /* It doesn't seem to be a correct start of a mac-address... */ + printk("(change MAC=[%02X %02X %02X]->[%02X %02X %02X])", + SA_prom[0], SA_prom[1], SA_prom[2], + ne_defethaddr[0],ne_defethaddr[1],ne_defethaddr[2]); + SA_prom[0] = ne_defethaddr[0]; + SA_prom[1] = ne_defethaddr[1]; + SA_prom[2] = ne_defethaddr[2]; + } + } +#endif /* CONFIG_M5206e */ + +#if !(defined(CONFIG_M5206e) && defined(CONFIG_NETtel)) if (wordlength == 2) { +#ifndef CONFIG_COLDFIRE for (i = 0; i < 16; i++) SA_prom[i] = SA_prom[i+i]; +#endif /* We must set the 8390 for word mode. */ outb_p(DCR_VAL, ioaddr + EN0_DCFG); start_page = NESM_START_PG; @@ -414,6 +537,12 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) start_page = NE1SM_START_PG; stop_page = NE1SM_STOP_PG; } +#endif +#if defined(CONFIG_CPU_H8300H) + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + H8300_INIT_NE(); +#endif #if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) @@ -494,6 +623,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); +#ifdef CONFIG_COLDFIRE + if (ret == 0) + ne2000_irqsetup(dev->irq); +#endif if (ret) { printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); goto err_out; @@ -552,7 +685,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) out_irq: free_irq(dev->irq, dev); err_out: +#if !defined(CONFIG_COLDFIRE) && !defined(CONFIG_CPU_H8300H) release_region(ioaddr, NE_IO_EXTENT); +#endif return ret; } @@ -864,7 +999,9 @@ static void cleanup_card(struct net_device *dev) if (idev) pnp_device_detach(idev); free_irq(dev->irq, dev); +#if !defined(CONFIG_COLDFIRE) && !defined(CONFIG_CPU_H8300H) release_region(dev->base_addr, NE_IO_EXTENT); +#endif } void cleanup_module(void) diff --git a/drivers/net/ns83865phy.h b/drivers/net/ns83865phy.h new file mode 100644 index 00000000..5659b005 --- /dev/null +++ b/drivers/net/ns83865phy.h @@ -0,0 +1,98 @@ +/*-------------------------------------------------------------------- + + * ns83865.h + + * + + * National NS83865 specific ethernet transceiver phy registers (09-31) + + * + + * Copyright (C) 2004 Microtronix Datacom 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. + + * + + * Apr2004 DGT Microtronix Datacom + + * + + ---------------------------------------------------------------------*/ + + + +#ifndef _NS883865PHY_H_ + + #define _NS883865PHY_H_ + + + +// Link Status Register + +#define NS883865_LNKSTS_REG 0x11 // Phy Reg17 + +// + +#define NS883865_LNKSTS_100_MASK 0x0008 // 100 Mbps + +#define NS883865_LNKSTS_LNKUP_MASK 0x0004 // Link Up + +#define NS883865_LNKSTS_FDUPLX_MASK 0x0002 // Full duplex + + + +// Interrupt Status Register + +#define NS883865_INTSTS_REG 0x14 // Phy Reg20 + +// + +#define NS883865_INTSTS_LSCHG_MASK 0x4000 // Link status change + +#define NS883865_INTSTS_ANEGDONE_MASK 0x0010 // Auto neg done + + + +// Interrupt Enable Register + +#define NS883865_INTIE_REG 0x15 // Phy Reg21 + +// + +#define NS883865_INTIE_LSCHG_MASK NS883865_INTSTS_LSCHG_MASK + +#define NS883865_INTIE_ANEGDONE_MASK NS883865_INTSTS_ANEGDONE_MASK + + + +// Interrupt Ack Register + +#define NS883865_INTACK_REG 0x17 // Phy Reg23 + +// + +#define NS883865_INTACK_LSCHG_MASK NS883865_INTSTS_LSCHG_MASK + +#define NS883865_INTACK_ANEGDONE_MASK NS883865_INTSTS_ANEGDONE_MASK + +#endif /* _NS883865PHY_H_ */ + diff --git a/drivers/net/open_eth.c b/drivers/net/open_eth.c new file mode 100644 index 00000000..097799c3 --- /dev/null +++ b/drivers/net/open_eth.c @@ -0,0 +1,2209 @@ +/*-------------------------------------------------------------------- + * open_eth.c + * + * Ethernet driver for Open Ethernet Controller (www.opencores.org). + * + * Based on: + * + * Ethernet driver for Motorola MPC8xx. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU + * + * Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev + * + * Copyright (c) 2002 Simon Srot (simons@opencores.org) + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * History: + * Jun/20/2004 DGT Microtronix Datacom NiosII + * + ---------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------- + * Rigt now XXBUFF_PREALLOC must be used, bacause MAC does not + * handle unaligned buffers yet. Also the cache inhibit calls + * should be used some day. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define ANNOUNCEPHYINT +//#undef ANNOUNCEPHYINT + +#ifdef CONFIG_EXCALIBUR + #include + #include + #define _print printk + #define MACIRQ_NUM na_igor_mac_irq + #define PHYIRQ_NUM na_mii_irq_irq + #define ETH_BASE_ADD na_igor_mac + #ifdef na_mii_irq + #define PHYIRQ_BASE_ADDR na_mii_irq + #else + #ifdef na_mii_irq_base + #define PHYIRQ_BASE_ADDR na_mii_irq_base + #else + ...?... + #endif + #endif + #define TDK78Q2120PHY + #define NUM_PHY_REGS 19 + /* Numbered 0, 1, ... (NUM_PHY_REGS - 1) */ +// #define PHY_ADDRESS 0x1F + // TDK78Q2120PHY's respond to the "'broadcast" phy address 0 + #define PHY_ADDRESS 0x00 +#endif // CONFIG_EXCALIBUR + +#include "open_eth.h" + +#define __clear_user(add,len) memset((add),0,(len)) + +#define OETH_DEBUG 0 +//#define OETH_DEBUG 1 + +#if OETH_DEBUG > 1 + #define PRINTK2(args...) printk(args) +#else + #define PRINTK2(args...) +#endif // OETH_DEBUG > 1 + +#ifdef OETH_DEBUG + #define PRINTK(args...) printk(args) +#else + #define PRINTK(args...) +#endif // OETH_DEBUG + +#undef SANCHKEPKT +//#define SANCHKEPKT + +#define RXBUFF_PREALLOC 1 +#define TXBUFF_PREALLOC 1 + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +/* Buffer number (must be 2^n) + */ +//;dgt;;;#define OETH_RXBD_NUM 8 +#define OETH_RXBD_NUM 16 +//;dgt;;;#define OETH_TXBD_NUM 8 +#define OETH_TXBD_NUM 16 + +#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) +#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) + +/* Buffer size + */ +#define OETH_RX_BUFF_SIZE 2048 +#define OETH_TX_BUFF_SIZE 2048 + +/* How many buffers per page + */ +#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE) +#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE) + +/* How many pages is needed for buffers + */ +#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE) +#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE) + +/* Buffer size (if not XXBUF_PREALLOC + */ +#define MAX_FRAME_SIZE 1518 + +#ifdef CONFIG_EXCALIBUR + #define TOTBYTSALLRXBUFS (OETH_RXBD_NUM * OETH_RX_BUFF_SIZE) + #define TOTBYTSALLTXBUFS (OETH_TXBD_NUM * OETH_TX_BUFF_SIZE) + #define TOTBYTSALLBUFS (TOTBYTSALLRXBUFS + TOTBYTSALLTXBUFS) + #if(na_sram_size >= TOTBYTSALLBUFS) + #define SRAM_BUFF 1 + #define SRAM_BUFF_BASE (na_sram_base) + #else + #undef SRAM_BUFF + #undef SRAM_BUFF_BASE + #endif +#else + //#define SRAM_BUFF 1 + //#define SRAM_BUFF_BASE (FBMEM_BASE_ADD + 0x80000) +#endif + +/* The buffer descriptors track the ring buffers. + */ +struct oeth_private { + struct sk_buff *rx_skbuff[OETH_RXBD_NUM]; + struct sk_buff *tx_skbuff[OETH_TXBD_NUM]; + + ushort tx_next; /* Next buffer to be sent */ + ushort tx_last; /* Next buffer to be checked if packet sent */ + ushort tx_full; /* Buffer ring fuul indicator */ + ushort rx_cur; /* Next buffer to be checked if packet received */ + + oeth_regs *regs; /* Address of controller registers. */ + oeth_bd *rx_bd_base;/* Address of Rx BDs. */ + oeth_bd *tx_bd_base;/* Address of Tx BDs. */ + + struct net_device_stats stats; +}; + +#ifdef SANCHKEPKT + + #ifndef UCHAR + #define UCHAR unsigned char + #endif // UCHAR + + #ifndef USHORT + #define USHORT unsigned short + #endif // USHORT + + #ifndef ULONG + #define ULONG unsigned long + #endif // ULONG + + #ifndef IP_TYPE_HFMT + #define IP_TYPE_HFMT 0x0800 + #endif // IP_TYPE_HFMT + + #ifndef ICMP_PROTOCOL + #define ICMP_PROTOCOL 1 + #endif // ICMP_PROTOCOL + + #ifndef TCP_PROTOCOL + #define TCP_PROTOCOL 6 + #endif // TCP_PROTOCOL + + #ifndef UDP_PROTOCOL + #define UDP_PROTOCOL 17 + #endif // UDP_PROTOCOL + + #ifdef CONFIG_EXCALIBUR + + #define read_b8(addr) (*(volatile unsigned char *) (addr)) + + #define rd8(addr) read_b8((volatile unsigned char *) (addr)) + + static USHORT read_w16(volatile USHORT *addr) + { + if((((ULONG) (addr)) & 0x00000001) == 0) + { + return *((volatile USHORT *) (addr)); + } + else + { + return (rd8( addr) | + (rd8(((unsigned char *) addr) + 1) << 8)); + } + } + + #define rd16(addr) read_w16((volatile USHORT *) (addr)) + +// static ULONG read_l32(volatile ULONG *addr) +// { +// if((((ULONG) (addr)) & 0x00000003) == 0) +// { +// return *((volatile ULONG *) (addr)); +// } +// else +// { +// return (rd16( addr) | +// (rd16(((((unsigned char *) addr) + 2))) << 16)); +// } +// } +// +// #define rd32(addr) read_l32((volatile ULONG *) (addr)) + + #endif // CONFIG_EXCALIBUR + + USHORT onessum(const UCHAR *buf, + const USHORT len, + const USHORT inisum) + { + USHORT iLen16 = (len >> 1); + USHORT iLen2_8; + USHORT i; + ULONG finalsum; + ULONG sum = inisum; + USHORT din; + + iLen2_8 = (iLen16 << 1); + + for (i = 0; i < iLen2_8; i += 2) + { + din = htons(rd16(buf + i)); + sum = sum + din; + } + + if((len & 1) != 0) + { + sum = sum + ((buf [iLen2_8]) << 8); + } + + finalsum = (sum & 0xffff) + ((sum >> 16) & 0xffff); + + sum = (finalsum & 0xffff) + ((finalsum >> 16) & 0xffff); + // Addition of carries can in turn produce yet another + // (at the most 1) carry (whose addition in turn can + // produce no further carries). + + sum &= 0xffff; + + /* (Final) caller must complement our return value (and, if, */ + /* applicable, complement once again if zero and Udp) */ + + return (USHORT)sum; + } + + USHORT psuchksum(const UCHAR *tcpudpbuf, + const USHORT tcpudplen, + const UCHAR *ipbuf, + const USHORT uoset2chksm) + { + unsigned int uiChksum; + unsigned int uiTmp; + + + // Tcp/Udp pseudo header + + uiChksum = onessum((ipbuf + 0x0C),4, 0); + + uiChksum = onessum((ipbuf + 0x10),4, uiChksum); + + uiTmp = ((ipbuf [0x09]) << 8); + uiChksum = onessum(((UCHAR *) (&(uiTmp))),2, uiChksum); + + uiTmp = htons(tcpudplen); + uiChksum = onessum(((UCHAR *) (&(uiTmp))),2, uiChksum); + // Txp/Udp message length, including real header + + // Real header and payload + + uiChksum = onessum(tcpudpbuf, + uoset2chksm, + uiChksum); + + uiChksum = (onessum((tcpudpbuf + (uoset2chksm + 2)), + (tcpudplen - (uoset2chksm + 2)), + uiChksum) + ^ 0xffff); + + if(uoset2chksm == 6) + { + /* UDP */ + + if(uiChksum == 0) + { + uiChksum = 0xFFFF; + } + } + + return uiChksum; + } + + USHORT icmpchksum(const UCHAR *icmpbuf, + const USHORT icmplen) + { + unsigned int uiChksum; + + + uiChksum = onessum(icmpbuf, + 0x02, + 0); + + uiChksum = (onessum((icmpbuf + 0x04), + (icmplen - + 0x04), + uiChksum) + ^ 0xffff); + + return uiChksum; + } + + USHORT ipchksum(const UCHAR *iphdrbuf, + const USHORT iphdrlen) + { + unsigned int uiChksum; + + + uiChksum = onessum(iphdrbuf, + 0x0A, + 0); + + uiChksum = (onessum((iphdrbuf + 0x0C), + (iphdrlen - + 0x0C), + uiChksum) + ^ 0xffff); + + return uiChksum; + } + + static void DoSanchkEpkt(const char *ptrEpkt, + const unsigned long ulBytcntNOcrc, + const char *ptrBfnam) + { + int iActChksum; + int iExptdChksum; + int iLenIphdrbyts; + int iLenIpinclhdrbyts; + + if(ulBytcntNOcrc >= 0x12) + { + if(rd16(&(ptrEpkt [0x0C])) == htons(IP_TYPE_HFMT)) + { + unsigned short ui16motoipflgsfrgo; + + // Bluebook etyp 0x0008 (Moto(0x0800)) = IP + + if(((ptrEpkt [0x0E]) & 0xF0) == 0x40) + { + // IP version 4 + + iLenIphdrbyts = ((ptrEpkt [0x0E]) & 0x0F) * 4; + + iLenIpinclhdrbyts = + ntohs(rd16(&(ptrEpkt [0x10]))); + + if((iLenIphdrbyts >= 20) && + (iLenIpinclhdrbyts >= iLenIphdrbyts) && + (ulBytcntNOcrc >= (iLenIpinclhdrbyts + 0x0E))) + // Dix Machdr 14 bytes + { + iExptdChksum = ipchksum(&(ptrEpkt [0x0E]), + iLenIphdrbyts); + + iActChksum = ntohs(rd16(&(ptrEpkt [0x18]))); + + if(iActChksum != iExptdChksum) + { + if((iExptdChksum != 0x0000) && + (iExptdChksum != 0xFFFF) && + (iActChksum != 0x0000) && + (iActChksum != 0xFFFF)) + { + printk("\n...IP %s{0x%08X} xptd" + " csum: 0x%04X" + ", 0x%04X seen (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + iExptdChksum, + iActChksum, + ulBytcntNOcrc); + + return; + } + } + } + else + { + printk("\n...Malformed IP %s{0x%08X}" + " header (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + ulBytcntNOcrc); + + return; + } + + ui16motoipflgsfrgo = rd16(&(ptrEpkt [0x14])); + + if((ntohs(ui16motoipflgsfrgo) & 0x2000) == 0) + { + /* Final or only IP fragment */ + + if(((ntohs(ui16motoipflgsfrgo) & 0x1FFF)) == 0) + { + // One and only IP fragment + + if(ptrEpkt [0x17] == ICMP_PROTOCOL) + { + // IP payload 0x01 = ICMP + + if((iLenIpinclhdrbyts - iLenIphdrbyts) >= 4) + { + iExptdChksum = + icmpchksum(&(ptrEpkt + [0x0E + + iLenIphdrbyts]), + (iLenIpinclhdrbyts - + iLenIphdrbyts)); + + iActChksum = + ntohs(rd16(&(ptrEpkt + [0x0E + + iLenIphdrbyts + + 2]))); + + if(iActChksum != iExptdChksum) + { + if((iExptdChksum != 0x0000) && + (iExptdChksum != 0xFFFF) && + (iActChksum != 0x0000) && + (iActChksum != 0xFFFF)) + { + printk("\n...ICMP %s{0x%08X}" + " xptd csum:" + " 0x%04X, 0x%04X" + " seen (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + iExptdChksum, + iActChksum, + ulBytcntNOcrc); + + return; + } + } + } + else + { + printk("\n...Malformed ICMP" + " %s{0x%08X}" + " pkt (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + ulBytcntNOcrc); + + return; + } + + return; + } + + if(ptrEpkt [0x17] == TCP_PROTOCOL) + { + // IP payload 0x06 = TCP + + if((iLenIpinclhdrbyts - iLenIphdrbyts) >= 20) + { + iActChksum = + ntohs(rd16(&(ptrEpkt [0x0E + + iLenIphdrbyts + + 16]))); + + iExptdChksum = + psuchksum(&(ptrEpkt + [0x0E + + iLenIphdrbyts]), + (iLenIpinclhdrbyts - + iLenIphdrbyts), + &(ptrEpkt [0x0E]), + 16); + + if(iActChksum != iExptdChksum) + { + printk("\n...TCP %s{0x%08X}" + " xptd csum:" + " 0x%04X, 0x%04X" + " seen (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + iExptdChksum, + iActChksum, + ulBytcntNOcrc); + + return; + } + } + else + { + printk("\n...Malformed TCP" + " %s{0x%08X}" + " pkt (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + ulBytcntNOcrc); + + return; + } + } + + if(ptrEpkt [0x17] == UDP_PROTOCOL) + { + // IP payload 0x11 = UDP + + if((iLenIpinclhdrbyts - iLenIphdrbyts) >= 8) + { + iActChksum = + ntohs(rd16(&(ptrEpkt [0x0E + + iLenIphdrbyts + + 6]))); + + if(iActChksum != 0x0000) + { + iExptdChksum = + psuchksum(&(ptrEpkt + [0x0E + + iLenIphdrbyts]), + (iLenIpinclhdrbyts - + iLenIphdrbyts), + &(ptrEpkt [0x0E]), + 6); + + if(iActChksum != iExptdChksum) + { + printk("\n...UDP %s{0x%08X}" + " xptd csum:" + " 0x%04X, 0x%04X" + " seen (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + iExptdChksum, + iActChksum, + ulBytcntNOcrc); + + return; + } + } + } + else + { + printk("\n...Malformed UDP" + " %s{0x%08X}" + " pkt (%ld ebyts)\n", + ptrBfnam, + ((unsigned long) ptrEpkt), + ulBytcntNOcrc); + + return; + } + } + } + else + { + // Final of many IP fragments + } + + return; + } + else + { + // One of many IP fragments + + return; + } + } + + return; + } + } + + return; + } +#endif // SANCHKEPKT + +#if OETH_DEBUG +static void +oeth_print_packet(unsigned long add, int len) +{ + int i; + + _print("ipacket: add = %x len = %d\n", add, len); + for(i = 0; i < len; i++) { + if(!(i % 16)) + _print("\n"); + _print(" %.2x", *(((unsigned char *)add) + i)); + } + _print("\n"); +} +#endif + +// Read a phy register +#if defined(TDK78Q2120PHY) +int eth_mdread(struct net_device *dev, + int fiad_phy_addr, + int phyreg) + { + int rdata; + volatile oeth_regs *regs = (oeth_regs *)dev->base_addr; + + // ensure busy not set + do + { + rdata = regs->miistatus; + + } while (rdata & OETH_MIISTATUS_BUSY); + + regs->miiaddress = ((unsigned long) (((phyreg << 8) | + fiad_phy_addr))); + regs->miicommand = ((unsigned long) (OETH_MIICOMMAND_RSTAT)); + + // wait while busy set + do + { + rdata = regs->miistatus; + + } while (rdata & OETH_MIISTATUS_BUSY); + + rdata = regs->miirx_data; + + return rdata; + } +#else + ...?... +#endif + +// Write a phy register +#if defined(TDK78Q2120PHY) +void eth_mdwrite(struct net_device *dev, + int fiad_phy_addr, + int phyreg, + int wdata) + { + int rdata; + volatile oeth_regs *regs = (oeth_regs *)dev->base_addr; + + // ensure busy not set + do + { + rdata = regs->miistatus; + + } while (rdata & OETH_MIISTATUS_BUSY); + + regs->miiaddress = ((unsigned long) (((phyreg << 8) | + fiad_phy_addr))); + regs->miitx_data = ((unsigned long) (wdata)); + regs->miicommand = ((unsigned long) (OETH_MIICOMMAND_WCTRLDATA)); + + // wait while busy set + do + { + rdata = regs->miistatus; + + } while (rdata & OETH_MIISTATUS_BUSY); + + return; + } +#else + ...?... +#endif + +void oeth_phymac_synch (struct net_device *dev, int callerflg) + { + volatile oeth_regs *regs = (oeth_regs *)dev->base_addr; + unsigned long ulmoderval; + unsigned long ulmr1sts; + unsigned long ulphydiagval; + + ulmr1sts = eth_mdread(dev, PHY_ADDRESS, 1); + /* Read twice to get CURRENT status */ + ulmr1sts = eth_mdread(dev, PHY_ADDRESS, 1); + + ulmoderval = regs->moder; + + #if defined(TDK78Q2120PHY) + ulphydiagval = eth_mdread(dev, PHY_ADDRESS, 18); + #else + ...?... + #endif + + if(callerflg == 0) + { + // Caller = NOT Phy interrupt handler + + if((ulmr1sts & 0x00000004) != 0) + { + // Link is ostensibly OK + + if((eth_mdread(dev, PHY_ADDRESS, 0) & 0x00001000) != 0) + { + // Auto negotiation ostensibly enabled + + if((ulmr1sts & 0x00000020) != 0) + { + // Auto negotiation ostensibly has completed + + #if defined(TDK78Q2120PHY) + + if((ulphydiagval & 0x1000) != 0) + { + // Auto negotiation ostensibly has failed + + if((ulphydiagval & (0x0800 | 0x0400 )) != 0) + { + // Auto negotiation failure expected to + // have fallen back to 10 mbit half + // duplex - perhaps phy registers aren't + // actually available, and we've been + // reading 0xFFFF's ? + + // A 10 mbit, 1/2 duplex remote partner + // mandates a 1/2 duplex Emac (else any + // amount of traffic at all will almost + // certainly collide up a storm...) + // 100 mbit remote partners seem to allow + // duplex mismatches without severe + // loss, at least at the low end of + // their nominal capacity. + // A 10 mbit, full duplex remote partner + // probably also requires a matched Emac, + // but hasn't been confirmed... + + printk("\noeth_phymac_synch:%s" + " No phyregs?-assuming HalfD\n", + dev->name); + + regs->moder = + ((unsigned long) + (ulmoderval & + (~(OETH_MODER_FULLD)))); + // FIXME:... + // ...Note manual says not supposed + // ... to "change registers after ModeR's + // ... TxEn or RxEn bit(s) have been set" + regs->ipgt = ((unsigned long) (0x00000012)); + + return; + } + } + #else + ...?... + #endif + } + } + } + } +// else +// { +// // Caller = Phy interrupt handler +// // If we've got a phy interrupt, then we're so likely +// // to also have actual phy registers that we won't +// // bother trying to confirm. +// } + + #if defined(ANNOUNCEPHYINT) + printk("\noeth_phymac_synch:%s MR1: 0x%08lX\n", + dev->name, + ulmr1sts); + if((ulmr1sts & 0x00000002) != 0) + { + printk(" Jabber\n"); + } + if((ulmr1sts & 0x00000010) != 0) + { + printk(" Remote Fault\n"); + } + if((ulmr1sts & 0x00000020) != 0) + { + printk(" Autoneg'd\n"); + } + #endif + + if((ulmr1sts & 0x00000004) != 0) + { + /* Phy MR1 (status register) indicates link is (now) OK. */ + + /* (dgt:07FEB2003) miistatus: */ + /* ...will NOT show current OETH_MIISTATUS_LINKFAIL */ + /* ... status, no matter how many times it's read... */ + /* ...one must first read phy status register (MR1), */ + /* ... then read miistatus... */ + /* ... so, we just use phy status directly. */ + + #if defined(ANNOUNCEPHYINT) + printk(" Link OK: MODER: 0x%08lX\n", + ulmoderval); + #endif + + /* Recommended ipgt register (0x000c) value: + * Back to Back Inter Packet Gap + * Full Duplex: 0x15: 0.96 uSecs IPG for 100 mbps + * 9.60 uSecs IPG for 10 mbps + * Desired period in nibble times minus 6 + * 96 bits = 24 nibbles - 6 = 18 = 0x12 (but + * reference guide says 0x15 (what's backwards, + * 6, or 0x15 ?)) + * Half Duplex: 0x12: 0.96 uSecs IPG for 100 mbps + * 9.60 uSecs IPG for 10 mbps + * Desired period in nibble times minus 3 + * 96 bits = 24 nibbles - 3 = 21 = 0x15 (but + * reference guide says 0x12 (what's backwards, + * 3, or 0x12 ?)) + */ + + #if defined(TDK78Q2120PHY) + + if((ulphydiagval & 0x0800) != 0) + { + /* Phy MR18 (diagnostics register) indicates */ + /* link is (now) running full duplex. */ + + if((ulmoderval & (OETH_MODER_FULLD)) == 0) + { + regs->moder = ((unsigned long) (ulmoderval | + (OETH_MODER_FULLD))); + } + // FIXME:... + // ...Note manual says not supposed to "change + // ... registers after ModeR's TxEn or RxEn + // ... bit(s) have been set" + if(regs->ipgt != ((unsigned long) (0x00000015))) + { + regs->ipgt = ((unsigned long) (0x00000015)); + } + + #if defined(ANNOUNCEPHYINT) + printk(" FullD: MR18: 0x%08lX\n", + ulphydiagval); + #endif + } + else + { + /* Phy MR18 (diagnostics register) indicates */ + /* link is (now) running half duplex. */ + + if((ulmoderval & (OETH_MODER_FULLD)) != 0) + { + regs->moder = ((unsigned long) (ulmoderval & + (~(OETH_MODER_FULLD)))); + } + // FIXME:... + // ...Note manual says not supposed to "change + // ... registers after ModeR's TxEn or RxEn + // ... bit(s) have been set" + if(regs->ipgt != ((unsigned long) (0x00000012))) + { + regs->ipgt = ((unsigned long) (0x00000012)); + } + + #if defined(ANNOUNCEPHYINT) + printk(" HalfD: MR18: 0x%08lX\n", + ulphydiagval); + #endif + } + + #if defined(ANNOUNCEPHYINT) + printk(" %s\n", + (ulphydiagval & 0x0400) ? "100BASE-TX" : "10BASE-T"); + #endif + #else + ...?... + #endif + } + #if defined(ANNOUNCEPHYINT) + else + { + printk(" Link Down\n"); + } + #endif + + #if defined(ANNOUNCEPHYINT) + printk("\n"); + #endif + + return; + } + +#if defined(PHYIRQ_NUM) +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t oeth_PhyInterrupt(int irq, + void *dev_id, + struct pt_regs *regs) + { + #if defined(TDK78Q2120PHY) + + unsigned long ulmr17sts; + struct net_device *dev = dev_id; + volatile struct oeth_private *cep; + + cep = (struct oeth_private *)dev->priv; + + ulmr17sts = eth_mdread(((struct net_device *) dev_id), + PHY_ADDRESS, 17); + // Read Clears (no ack req'd) + + if((ulmr17sts & 0x00000040) != 0) + { + cep->stats.rx_frame_errors++; + } + + #if defined(ANNOUNCEPHYINT) + printk("\noeth_PhyInterrupt:%s MR17: 0x%08lX\n", + dev->name, + ulmr17sts); + if((ulmr17sts & 0x00000080) != 0) + { + printk(" Jabber\n"); + } + if((ulmr17sts & 0x00000040) != 0) + { + printk(" Rxer\n"); + } + if((ulmr17sts & 0x00000020) != 0) + { + printk(" Pagerec\n"); + } + if((ulmr17sts & 0x00000010) != 0) + { + printk(" Pfd\n"); + } + if((ulmr17sts & 0x00000008) != 0) + { + printk(" Lpack\n"); + } + if((ulmr17sts & 0x00000004) != 0) + { + printk(" Lschg\n"); + } + if((ulmr17sts & 0x00000002) != 0) + { + printk(" Rfault\n"); + } + if((ulmr17sts & 0x00000001) != 0) + { + printk(" Anegcomp\n"); + } + #endif + + oeth_phymac_synch((struct net_device *) dev_id, + 1); // Caller = Phy interrupt handler + #else + ...?... + #endif + + return IRQ_HANDLED; + } +#endif // PHYIRQ_NUM + + +/* + Entered at interrupt level +*/ +static void +oeth_tx(struct net_device *dev) +{ + volatile struct oeth_private *cep; + volatile oeth_bd *bdp; + +#ifndef TXBUFF_PREALLOC + struct sk_buff *skb; +#endif + + cep = (struct oeth_private *)dev->priv; + + for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK) + { + bdp = cep->tx_bd_base + cep->tx_last; + + if ((bdp->len_status & OETH_TX_BD_READY) || + ((cep->tx_last == cep->tx_next) && !cep->tx_full)) + break; + + /* Check status for errors + */ + if (bdp->len_status & OETH_TX_BD_LATECOL) + cep->stats.tx_window_errors++; + //;dgt - ifconfig doesn't report tx_window_errors ? + //;dgt - but we (also) include same in tx_errors. + + if (bdp->len_status & OETH_TX_BD_RETLIM) + cep->stats.tx_aborted_errors++; + //;dgt - ifconfig doesn't report tx_aborted_errors ? + //;dgt - but we (also) include same in tx_errors. + + if (bdp->len_status & OETH_TX_BD_UNDERRUN) + cep->stats.tx_fifo_errors++; + + if (bdp->len_status & OETH_TX_BD_CARRIER) + cep->stats.tx_carrier_errors++; + + //;dgt - OETH_TX_BD_DEFER neither counted nor ifconfig reported + + if (bdp->len_status & (OETH_TX_BD_LATECOL | + OETH_TX_BD_RETLIM | + OETH_TX_BD_UNDERRUN)) + cep->stats.tx_errors++; + + cep->stats.tx_packets++; + cep->stats.collisions += (bdp->len_status >> 4) & 0x000f; + +#ifndef TXBUFF_PREALLOC + skb = cep->tx_skbuff[cep->tx_last]; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb(skb); +#endif + + if (cep->tx_full) + cep->tx_full = 0; + } +} + +/* + Entered at interrupt level +*/ +static void +oeth_rx(struct net_device *dev) +{ + volatile struct oeth_private *cep; + volatile oeth_bd *bdp; + struct sk_buff *skb; + int pkt_len; + int bad; //;dgt + int netif_rx_rtnsts; //;dgt + #ifndef RXBUFF_PREALLOC + struct sk_buff *small_skb; + #endif + + cep = (struct oeth_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + for (;;cep->rx_cur = (cep->rx_cur + 1) & OETH_RXBD_NUM_MASK) + { + bad = 0; //;dgt + bdp = cep->rx_bd_base + cep->rx_cur; + + #ifndef RXBUFF_PREALLOC + skb = cep->rx_skbuff[cep->rx_cur]; + + if (skb == NULL) + { + skb = dev_alloc_skb(MAX_FRAME_SIZE); + + if (skb != NULL) + { + bdp->addr = (unsigned long) skb->tail; + + dcache_push (((unsigned long) (bdp->addr)), + MAX_FRAME_SIZE); + + bdp->len_status |= OETH_RX_BD_EMPTY; + } + + continue; + } + #endif + + if (bdp->len_status & OETH_RX_BD_EMPTY) + break; + + /* Check status for errors. + */ + if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { + cep->stats.rx_length_errors++; + //;dgt - ifconfig doesn't report rx_length_errors ? + //;dgt - but we (also) include same in rx_errors. + bad = 1; + } + if (bdp->len_status & OETH_RX_BD_DRIBBLE) { + cep->stats.rx_frame_errors++; + bad = 1; + } + if (bdp->len_status & OETH_RX_BD_CRCERR) { + cep->stats.rx_crc_errors++; + //;dgt - ifconfig doesn't report rx_crc_errors ? + //;dgt - but we (also) include same in rx_errors. + bad = 1; + } + if (bdp->len_status & OETH_RX_BD_OVERRUN) { + cep->stats.rx_crc_errors++; + //;dgt - ifconfig doesn't report rx_crc_errors ? + //;dgt - but we (also) include same in rx_errors. + bad = 1; + } + if (bdp->len_status & OETH_RX_BD_MISS) + { + //;dgt - identifies a packet received in promiscuous + //;dgt mode (would not have otherwise been accepted) + } + if (bdp->len_status & OETH_RX_BD_LATECOL) { + cep->stats.rx_frame_errors++; + bad = 1; + } + if (bdp->len_status & OETH_RX_BD_INVSIMB) { //;dgt + cep->stats.rx_frame_errors++; //;dgt + bad = 1; //;dgt + } //;dgt + if (bdp->len_status & (OETH_RX_BD_TOOLONG | //;dgt + OETH_RX_BD_SHORT | //;dgt + OETH_RX_BD_CRCERR | //;dgt + OETH_RX_BD_OVERRUN)) //;dgt + cep->stats.rx_errors++; //;dgt + + if (bad) + { + bdp->len_status &= ~OETH_RX_BD_STATS; + + dcache_push (((unsigned long) (bdp->addr)), + OETH_RX_BUFF_SIZE); + + bdp->len_status |= OETH_RX_BD_EMPTY; + + continue; + } + + /* Process the incoming frame. + */ + pkt_len = bdp->len_status >> 16; + +#ifdef RXBUFF_PREALLOC + #ifdef CONFIG_EXCALIBUR +//;dgt skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len + 2 + 3 + 4); //;dgt + //;dgt Over allocate 2 extra bytes to + //;dgt 32 bit align Nios 32 bit + //;dgt IP/TCP fields. + //;dgt Over allocate 3 extra bytes to + //;dgt allow packet to be treated as + //;dgt as an even number of bytes or + //;dgt 16 bit words if so desired. + //;dgt Plus another extra 4 paranoia bytes. + #else + skb = dev_alloc_skb(pkt_len); + #endif + + if (skb == NULL) + { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else + { + skb->dev = dev; +#if OETH_DEBUG + _print("RX\n"); + oeth_print_packet(bdp->addr, pkt_len); +#endif + #ifdef CONFIG_EXCALIBUR + { + unsigned short *dst; + unsigned short *src; + + #ifdef SANCHKEPKT + unsigned short *savddst; + #endif // SANCHKEPKT + + skb_reserve( skb, 2 ); + //;dgt 32 bit align Nios 32 bit IP/TCP fields + + dst = ((unsigned short *) (skb_put(skb, pkt_len))); + src = ((unsigned short *) (__va(bdp->addr))); + + #ifdef SANCHKEPKT + savddst = dst; + DoSanchkEpkt(((const char *) src), + pkt_len, + "DmaRx"); + #endif // SANCHKEPKT + + //;dgt...FIXME...simple 16 bit copy loop + //;dgt... = approx 20% overall throughput + //;dgt... improvement over memcpy... + //;dgt...A more advanced copy from 32 bit + //;dgt... aligned source to 16 bit aligned + //;dgt... destination still needed though... + //;dgt...Note destination bears enough extra + //;dgt... room to hold ((pkt_len + 3) >> 2) + //;dgt... longwords... + //;dgt;Mar2005;Custom NiosII instruction now + //;dgt; available or imminent for a "really" + //;dgt; optimized memcpy, even under mismatched + //;dgt; src/dst alignments + #if 0 + { + unsigned int uiloop; + for(uiloop = 0; + (uiloop < ((pkt_len + 1) >> 1)); + uiloop++) + { + *dst++ = *src++; + } + } + #else + memcpy(dst, src, pkt_len); + #endif + + #ifdef SANCHKEPKT + DoSanchkEpkt(((const char *) savddst), + pkt_len, + "SkbRx"); + #endif // SANCHKEPKT + } + #else + memcpy(skb_put(skb, pkt_len), + (unsigned char *)__va(bdp->addr), + pkt_len); + #endif + + skb->protocol = eth_type_trans(skb,dev); + + netif_rx_rtnsts = netif_rx(skb); //;dgt + + switch (netif_rx_rtnsts) //;dgt + { //;dgt + case NET_RX_DROP: // 0x01 //;dgt + cep->stats.rx_dropped++; //;dgt + // memo: netif_rx has: kfree_skb(skb); //;dgt + #if 0 //;dgt + printk("%s: netif_rx dropped" //;dgt + " %d byte packet.\n", //;dgt + dev->name, //;dgt + pkt_len); //;dgt + #endif //;dgt + break; //;dgt + #if 0 //;dgt + case NET_RX_SUCCESS: // 0x00 //;dgt + break; //;dgt + default: //;dgt +// case NET_RX_CN_LOW: // 0x02 //;dgt +// case NET_RX_CN_MOD: // 0x03 //;dgt +// case NET_RX_CN_HIGH: // 0x04 //;dgt +// case NET_RX_BAD: // 0x05 //;dgt + printk("%s: netif_rx rtnsts: %08lX\n", //;dgt + dev->name, //;dgt + netif_rx_rtnsts); //;dgt + break; //;dgt + #endif //;dgt + } //;dgt + + cep->stats.rx_packets++; + } + + dcache_push (((unsigned long) (bdp->addr)), + pkt_len); + + bdp->len_status &= ~OETH_RX_BD_STATS; + bdp->len_status |= OETH_RX_BD_EMPTY; +#else + if (pkt_len < 128) + { + small_skb = dev_alloc_skb(pkt_len); + + if (small_skb) + { + small_skb->dev = dev; + #if OETH_DEBUG + _print("RX short\n"); + oeth_print_packet(bdp->addr, bdp->len_status >> 16); + #endif + memcpy(skb_put(small_skb, pkt_len), + (unsigned char *)__va(bdp->addr), + pkt_len); + small_skb->protocol = eth_type_trans(small_skb,dev); + netif_rx(small_skb); + cep->stats.rx_packets++; + } + else + { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + + dcache_push (((unsigned long) (bdp->addr)), + pkt_len); + + bdp->len_status &= ~OETH_RX_BD_STATS; + bdp->len_status |= OETH_RX_BD_EMPTY; + } + else + { + skb->dev = dev; + skb_put(skb, bdp->len_status >> 16); + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + cep->stats.rx_packets++; + #if OETH_DEBUG + _print("RX long\n"); + oeth_print_packet(bdp->addr, bdp->len_status >> 16); + #endif + skb = dev_alloc_skb(MAX_FRAME_SIZE); + + bdp->len_status &= ~OETH_RX_BD_STATS; + + if (skb) + { + cep->rx_skbuff[cep->rx_cur] = skb; + + bdp->addr = (unsigned long)skb->tail; + + dcache_push (((unsigned long) (bdp->addr)), + MAX_FRAME_SIZE); + + bdp->len_status |= OETH_RX_BD_EMPTY; + } + else + { + cep->rx_skbuff[cep->rx_cur] = NULL; + } + } +#endif + } +} + + +/*----------------------------------------------------------- + | Driver entry point + | + | Entry condition: Cpu interrupts DISabled. + */ +static irqreturn_t oeth_interrupt(int irq, + void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + volatile struct oeth_private *cep; + uint int_events; + + cep = (struct oeth_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->regs->int_src; + cep->regs->int_src = int_events; + + /* Handle receive event in its own function. + */ + if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) + oeth_rx(dev_id); + + /* Handle transmit event in its own function. + */ + if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { + oeth_tx(dev_id); + + if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last) + { + netif_wake_queue(dev); + } +// else +// { +// Tx done interrupt but no tx BD's released ? +// } + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & OETH_INT_BUSY) + { + cep->stats.rx_dropped++; //;dgt + + if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) + { + oeth_rx(dev_id); + } + } + + return IRQ_HANDLED; +} + + +static int +oeth_open(struct net_device *dev) +{ + volatile oeth_regs *regs = (oeth_regs *)dev->base_addr; + +#ifndef RXBUFF_PREALLOC + volatile struct oeth_private *cep = (struct oeth_private *)dev->priv; + struct sk_buff *skb; + volatile oeth_bd *rx_bd; + int i; + + rx_bd = cep->rx_bd_base; + + for(i = 0; i < OETH_RXBD_NUM; i++) + { + skb = dev_alloc_skb(MAX_FRAME_SIZE); + + if (skb == NULL) + rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ; + else + dcache_push (((unsigned long) (rx_bd[i].addr)), + MAX_FRAME_SIZE); + + rx_bd[i].len_status = (0 << 16) | + OETH_RX_BD_EMPTY | + OETH_RX_BD_IRQ; + // FIXME...Should we really let the rx ring + // ... completely fill...?... + // ...Can we actually prevent...?... + + cep->rx_skbuff[i] = skb; + rx_bd[i].addr = (unsigned long)skb->tail; + } + rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; +#endif + + /* Install our interrupt handler. + */ + request_irq(MACIRQ_NUM, oeth_interrupt, 0, "eth", (void *)dev); + + // enable phy interrupts + // + #if defined(TDK78Q2120PHY) + #if defined(PHYIRQ_NUM) + request_irq(PHYIRQ_NUM, + oeth_PhyInterrupt, + 0, "eth", (void *)dev); + + eth_mdread (dev, PHY_ADDRESS, 17); // Clear any junk ? + + eth_mdwrite(dev, PHY_ADDRESS, 17, 0xff00); + // Enable Jabber 0x8000(0x0080) + // Rxer 0x4000(0x0040) + // Prx 0x2000(0x0020) + // Pfd 0x1000(0x0010) + // Lpack 0x0800(0x0008) + // Lschg 0x0400(0x0004) + // Rfault 0x0200(0x0002) + // Anegcomp 0x0100(0x0001) + // Ints + + (*(volatile unsigned long *) + (((unsigned long *) + ((((char *) + (((int) (PHYIRQ_BASE_ADDR)) + + 0x0008))))))) = + ((unsigned long) (0x0001)); + // Enable phy interrupt pass thru to PHYIRQ_NUM + #endif + #else + ...?... + #endif + + oeth_phymac_synch(dev, + 0); // Caller = NOT Phy interrupt handler + + /* Enable receiver and transmiter + */ + regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; + + netif_start_queue(dev); + + return 0; +} + +static int +oeth_close(struct net_device *dev) +{ + volatile struct oeth_private *cep = (struct oeth_private *)dev->priv; + volatile oeth_regs *regs = (oeth_regs *)dev->base_addr; + volatile oeth_bd *bdp; + int i; + + netif_stop_queue(dev); + + /* Free phy interrupt handler + */ + #if defined(TDK78Q2120PHY) + #if defined(PHYIRQ_NUM) + (*(volatile unsigned long *) + (((unsigned long *) + ((((char *) + (((int) (PHYIRQ_BASE_ADDR)) + + 0x0008))))))) = + ((unsigned long) (0x0000)); + // Disable phy interrupt pass thru to PHYIRQ_NUM + + free_irq(PHYIRQ_NUM, (void *)dev); + #endif + #else + ...?... + #endif + + /* Free interrupt hadler + */ + free_irq(MACIRQ_NUM, (void *)dev); + + /* Disable receiver and transmitesr + */ + regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); + + bdp = cep->rx_bd_base; + for (i = 0; i < OETH_RXBD_NUM; i++) { + bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY); + bdp++; + } + + bdp = cep->tx_bd_base; + for (i = 0; i < OETH_TXBD_NUM; i++) { + + bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY); + + bdp++; + } + +#ifndef RXBUFF_PREALLOC + + /* Free all alocated rx buffers + */ + for (i = 0; i < OETH_RXBD_NUM; i++) { + + if (cep->rx_skbuff[i] != NULL) + dev_kfree_skb(cep->rx_skbuff[i]); + + } +#endif // RXBUFF_PREALLOC + +#ifndef TXBUFF_PREALLOC + + /* Free all alocated tx buffers + */ + for (i = 0; i < OETH_TXBD_NUM; i++) { + + if (cep->tx_skbuff[i] != NULL) + dev_kfree_skb(cep->tx_skbuff[i]); + } +#endif // TXBUFF_PREALLOC + + return 0; +} + +static int +oeth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + volatile struct oeth_private *cep = (struct oeth_private *)dev->priv; + volatile oeth_bd *bdp; + unsigned long flags; + unsigned int lenSkbDataByts; + + netif_stop_queue(dev); + + if (cep->tx_full) { + //;dgt-"Impossible", but in any event, queue may have been + //;dgt- reawakened by now. + /* All transmit buffers are full. Bail out. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } + + lenSkbDataByts = skb->len; + + /* Fill in a Tx ring entry + */ + bdp = cep->tx_bd_base + cep->tx_next; + + /* Clear all of the status flags. + */ + bdp->len_status &= ~OETH_TX_BD_STATS; + + /* If the frame is short, tell CPM to pad it. + */ + if (lenSkbDataByts <= ETH_ZLEN) + bdp->len_status |= OETH_TX_BD_PAD; + else + bdp->len_status &= ~OETH_TX_BD_PAD; + +#if OETH_DEBUG + _print("TX\n"); + oeth_print_packet(skb->data, lenSkbDataByts); +#endif // OETH_DEBUG + +#ifdef TXBUFF_PREALLOC + + /* Copy data in preallocated buffer */ + if (lenSkbDataByts > OETH_TX_BUFF_SIZE) + { + printk("%s: %d byte tx frame too long (max:%d)!.\n", + dev->name, + lenSkbDataByts, + OETH_TX_BUFF_SIZE); + +//;dgt return 1; //;dgt infinite loop! + dev_kfree_skb(skb); //;dgt + netif_wake_queue(dev); + return 0; //;dgt + } + else + { + #ifdef CONFIG_EXCALIBUR + #ifdef SANCHKEPKT + DoSanchkEpkt(((const char *) (skb->data)), + lenSkbDataByts, + "SkbTx"); + #endif // SANCHKEPKT + + if((((unsigned long) (skb->data)) & 1) == 0) + { + unsigned short *dst; + unsigned short *src; + + dst = ((unsigned short *) (bdp->addr)); + src = ((unsigned short *) (skb->data)); + + //;dgt...FIXME...simple 16 bit copy loop + //;dgt... = approx 20% overall throughput + //;dgt... improvement... + //;dgt...A more advanced copy from 16 bit + //;dgt... aligned source to 32 bit aligned + //;dgt... destination still needed though... + //;dgt;Mar2005;Custom NiosII instruction now + //;dgt; available or imminent for a "really" + //;dgt; optimized memcpy, even under mismatched + //;dgt; src/dst alignments + #if 0 + { + unsigned int uiloop; + for(uiloop = 0; + (uiloop < (lenSkbDataByts >> 1)); + uiloop++) + { + *dst++ = *src++; + } + + if(((lenSkbDataByts) & 1) != 0) + { + *((unsigned char *) dst) = + *((unsigned char *) src); + } + } + #else + memcpy(dst, src, lenSkbDataByts); + #endif + } + else + { + memcpy((unsigned char *)bdp->addr, + skb->data, + lenSkbDataByts); + } + + #ifdef SANCHKEPKT + DoSanchkEpkt(((const char *) (bdp->addr)), + lenSkbDataByts, + "DmaTx"); + #endif // SANCHKEPKT + + #else + memcpy((unsigned char *)bdp->addr, skb->data, lenSkbDataByts); + #endif // CONFIG_EXCALIBUR + } + + bdp->len_status = (bdp->len_status & 0x0000ffff) + | (lenSkbDataByts << 16); + + dev_kfree_skb(skb); +#else + /* Set buffer length and buffer pointer. + */ + bdp->len_status = (bdp->len_status & 0x0000ffff) + | (lenSkbDataByts << 16); + bdp->addr = (uint)__pa(skb->data); + + /* Save skb pointer. + */ + cep->tx_skbuff[cep->tx_next] = skb; +#endif // TXBUFF_PREALLOC + +//;dgt cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK; + + local_irq_save(flags); + + cep->tx_next = (cep->tx_next + 1) & OETH_TXBD_NUM_MASK; //;dgt + + if (cep->tx_next == cep->tx_last) + { + cep->tx_full = 1; + } + else + { + if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last) + { + netif_wake_queue(dev); + } +// else +// { +// Don't let the tx ring completely fill +// } + } + + /* Send it on its way. Tell controller its ready, interrupt when done, + * and to put the CRC on the end. + */ + dcache_push (((unsigned long) (bdp->addr)), + lenSkbDataByts); + + bdp->len_status |= ( 0 + | OETH_TX_BD_READY + | OETH_TX_BD_IRQ + | OETH_TX_BD_CRC + ); + + dev->trans_start = jiffies; + + local_irq_restore(flags); + + return 0; +} + + +#if 1 //;dgt + // //;dgt +#else //;dgt +static int calc_crc(char *mac_addr) +{ + // FIXME.... //;dgt + // ...must calculate the PRE postconditioned AutoDinII //;dgt + // ... Crc-32 of the 6 bytes pointed to by mac_addr, //;dgt + // ... then extract and reverse bit #'s 3-8 inclusive //;dgt + // ... (with due regard to the varying frames of reference //;dgt + // ... within various crc publications, etc)... //;dgt + // Eg: 01-80-C2-00-00-01 (IEEE 802 Mac control multicast) //;dgt + // CRC-32: 0x9FC42B70 before Postconditioning //;dgt + // Last_on_wire_9F 70_First (If were to go onto wire) //;dgt + // Bits #'s 0-16: 0x2B70 //;dgt + // .......98 7654 3210 //;dgt + // 0010 1011 0111 0000 //;dgt + // Bits #'s 3-8: 1 0111 0 //;dgt + // Reversed: 0 1110 1 = 0x1D //;dgt + // Return multicast hash bit offset: 29 decimal //;dgt + // Eg: 01-00-5E-00-00-09 (IETF Rip2 multicast) //;dgt + // CRC-32 0xD76F4DCC before Postconditioning //;dgt + // Return multicast hash bit offset: 39 decimal //;dgt + // At least it so appears. //;dgt + + int result = 0; + return (result & 0x3f); +} +#endif //;dgt + +static struct net_device_stats *oeth_get_stats(struct net_device *dev) +{ + volatile struct oeth_private *cep = (struct oeth_private *)dev->priv; + + return &cep->stats; +} + +static void oeth_set_multicast_list(struct net_device *dev) +{ + volatile struct oeth_private *cep; + volatile oeth_regs *regs; + + cep = (struct oeth_private *)dev->priv; + + /* Get pointer of controller registers. + */ + regs = (oeth_regs *)dev->base_addr; + + if (dev->flags & IFF_PROMISC) { + + /* Log any net taps. + */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + regs->moder |= OETH_MODER_PRO; + } else { + + regs->moder &= ~OETH_MODER_PRO; + + if (dev->flags & IFF_ALLMULTI) { + + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + regs->hash_addr0 = 0xffffffff; + regs->hash_addr1 = 0xffffffff; + } + else if (dev->mc_count) { + + #if 1 //;dgt + // FIXME...for now, until broken //;dgt + // calc_crc(...) fixed... //;dgt + regs->hash_addr0 = 0xffffffff; //;dgt + regs->hash_addr1 = 0xffffffff; //;dgt + #else //;dgt + struct dev_mc_list *dmi; + int i; + + /* Clear filter and add the addresses in the list. + */ + regs->hash_addr0 = 0x00000000; +//;dgt regs->hash_addr0 = 0x00000000; + regs->hash_addr1 = 0x00000000; //;dgt + + dmi = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++) { + + int hash_b; + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + hash_b = calc_crc(dmi->dmi_addr); + if(hash_b >= 32) + regs->hash_addr1 |= 1 << (hash_b - 32); + else + regs->hash_addr0 |= 1 << hash_b; + } + #endif //;dgt + } + } +} + +static void oeth_set_mac_add(struct net_device *dev, void *p) +{ + struct sockaddr *addr=p; + volatile oeth_regs *regs; + + memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); + + regs = (oeth_regs *)dev->base_addr; + + regs->mac_addr1 = (dev->dev_addr[0]) << 8 | + (dev->dev_addr[1]); + regs->mac_addr0 = (dev->dev_addr[2]) << 24 | + (dev->dev_addr[3]) << 16 | + (dev->dev_addr[4]) << 8 | + (dev->dev_addr[5]); +} + + +/*----------------------------------------------------------- + | Entry condition: Cpu interrupts ENabled + | (in SPITE of claims disabled). +*/ +static int __init oeth_probe(struct net_device *dev) +{ + volatile struct oeth_private *cep; + volatile oeth_regs *regs; + volatile oeth_bd *tx_bd, *rx_bd; + int i, j, k; + #ifdef SRAM_BUFF + unsigned long mem_addr = SRAM_BUFF_BASE; + #else + unsigned long mem_addr; + #endif // SRAM_BUFF + + PRINTK2("%s:oeth_probe\n", dev->name); + + SET_MODULE_OWNER (dev); + + cep = (struct oeth_private *)dev->priv; + + if (!request_region(OETH_REG_BASE, + OETH_IO_EXTENT, + dev->name)) return -EBUSY; + + printk("%s: Open Ethernet Core Version 1.0\n", dev->name); + + #ifdef CONFIG_EXCALIBUR + printk(" oeth_probe: %d Khz Nios: %d RX, %d TX", + nasys_clock_freq_1000, + OETH_RXBD_NUM, + OETH_TXBD_NUM); + #endif // CONFIG_EXCALIBUR + + dev->base_addr = OETH_REG_BASE; + + __clear_user(cep,sizeof(*cep)); + + /* Get pointer ethernet controller configuration registers. + */ + cep->regs = (oeth_regs *)(OETH_REG_BASE); + regs = (oeth_regs *)(OETH_REG_BASE); + + /* Reset the controller. + */ + regs->moder = OETH_MODER_RST; /* Reset ON */ + regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ + + /* Setting TXBD base to OETH_TXBD_NUM. + */ + regs->tx_bd_num = OETH_TXBD_NUM; + + /* Initialize TXBD pointer + */ + cep->tx_bd_base = (oeth_bd *)OETH_BD_BASE; + tx_bd = (volatile oeth_bd *)OETH_BD_BASE; + + /* Initialize RXBD pointer + */ + cep->rx_bd_base = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; + rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; + + /* Initialize transmit pointers. + */ + cep->rx_cur = 0; + cep->tx_next = 0; + cep->tx_last = 0; + cep->tx_full = 0; + + /* Set min/max packet length + */ + regs->packet_len = 0x00400600; + +//;dgt-see oeth_phymac_synch /* Set IPGT register to recomended value */ +//;dgt-see oeth_phymac_synch regs->ipgt = 0x00000012; + + /* Set IPGR1 register to recomended value + */ + regs->ipgr1 = 0x0000000c; + + /* Set IPGR2 register to recomended value + */ + regs->ipgr2 = 0x00000012; + + /* Set COLLCONF register to recomended value + */ + regs->collconf = 0x000f003f; + + /* Set control module mode + */ + #if 0 + regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; + #else + regs->ctrlmoder = 0; + #endif + + #if defined(TDK78Q2120PHY) + // TDK78Q2120 reset values: + // + // MR0 (Control): 0x3100: + // 0x00100 FullDuplexIfnoneg + // 0x01000 AutonegEnabled + // 0x02000 100BaseTxIfnoneg + // + // MR18 (Diagnostics): 0x0000 + + /* TDK78Q2120 LEDs (seven?) NOT configurable? */ + #else + ...Intel LXT971A phy...?... + + /* Set PHY to show Tx status, Rx status and Link status */ + regs->miiaddress = 20<<8; + regs->miitx_data = 0x1422; + regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; + #endif // TDK78Q2120PHY + +#ifdef TXBUFF_PREALLOC + + /* Initialize TXBDs. + */ + for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) { + + #ifndef SRAM_BUFF + mem_addr = __get_free_page(GFP_KERNEL); + #endif // SRAM_BUFF + + for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) { + tx_bd[k].len_status = OETH_TX_BD_PAD | + OETH_TX_BD_CRC | + OETH_RX_BD_IRQ; + tx_bd[k].addr = __pa(mem_addr); + mem_addr += OETH_TX_BUFF_SIZE; + } + } + tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; +#else + + /* Initialize TXBDs. + */ + for(i = 0; i < OETH_TXBD_NUM; i++) { + + cep->tx_skbuff[i] = NULL; + + tx_bd[i].len_status = (0 << 16) | + OETH_TX_BD_PAD | + OETH_TX_BD_CRC | + OETH_RX_BD_IRQ; + tx_bd[i].addr = 0; + } + tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; +#endif // TXBUFF_PREALLOC + +#ifdef RXBUFF_PREALLOC + + /* Initialize RXBDs. + */ + for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) { + + #ifndef SRAM_BUFF + mem_addr = __get_free_page(GFP_KERNEL); + #endif // SRAM_BUFF + + for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) + { + rx_bd[k].addr = __pa(mem_addr); + + dcache_push (((unsigned long) (rx_bd[k].addr)), + OETH_RX_BUFF_SIZE); + + rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; + // FIXME...Should we really let the rx ring + // ... completely fill...?... + // ...Can we actually prevent ? + + mem_addr += OETH_RX_BUFF_SIZE; + } + } + rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; + +#else + /* Initialize RXBDs. + */ + for(i = 0; i < OETH_RXBD_NUM; i++) + { + rx_bd[i].len_status = (0 << 16) | OETH_RX_BD_IRQ; + cep->rx_skbuff[i] = NULL; + rx_bd[i].addr = 0; + } + rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; + +#endif // RXBUFF_PREALLOC + + /* Set default ethernet station address. + */ + + #ifdef CONFIG_EXCALIBUR + { + extern unsigned char *excalibur_enet_hwaddr; + memcpy(dev->dev_addr, excalibur_enet_hwaddr, 6); + } + #else + dev->dev_addr[0] = MACADDR0; + dev->dev_addr[1] = MACADDR1; + dev->dev_addr[2] = MACADDR2; + dev->dev_addr[3] = MACADDR3; + dev->dev_addr[4] = MACADDR4; + dev->dev_addr[5] = MACADDR5; + #endif // CONFIG_EXCALIBUR + + regs->mac_addr1 = (dev->dev_addr[0]) << 8 | + (dev->dev_addr[1]); + regs->mac_addr0 = (dev->dev_addr[2]) << 24 | + (dev->dev_addr[3]) << 16 | + (dev->dev_addr[4]) << 8 | + (dev->dev_addr[5]); + + /* Clear all pending interrupts + */ + regs->int_src = 0xffffffff; + + /* Promisc, IFG, CRCEn + */ + regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN; + + /* Enable interrupt sources. + */ + regs->int_mask = OETH_INT_MASK_TXB | + OETH_INT_MASK_TXE | + OETH_INT_MASK_RXF | + OETH_INT_MASK_RXE | + OETH_INT_MASK_BUSY | + OETH_INT_MASK_TXC | + OETH_INT_MASK_RXC; + + /* Fill in the fields of the device structure with ethernet values. + */ + ether_setup(dev); + + dev->base_addr = (unsigned long)OETH_REG_BASE; + + /* The Open Ethernet specific entries in the device structure. + */ + dev->open = oeth_open; + dev->hard_start_xmit = oeth_start_xmit; + dev->stop = oeth_close; + dev->get_stats = oeth_get_stats; + dev->set_multicast_list = oeth_set_multicast_list; + dev->set_mac_address = oeth_set_mac_add; + +#ifdef CONFIG_EXCALIBUR + #ifdef SRAM_BUFF + printk(" SRAM @0x%08X",SRAM_BUFF_BASE); + #endif + printk(" buffs\n"); + printk(" %s Custom HW ALIGN.\n", + #if defined(ALT_CI_ALIGN_32_N) + "WITH" + #else + "NO" + #endif + ); + printk(" CONFIG_NIOS2_HW_MULX %sdefined.\n", + #ifdef CONFIG_NIOS2_HW_MULX + "" + #else + "NOT " + #endif + ); + printk(" CONFIG_NIOS2_HW_MUL_OFF %sdefined.\n", + #ifdef CONFIG_NIOS2_HW_MUL_OFF + "" + #else + "NOT " + #endif + ); +#endif +#ifdef SANCHKEPKT + printk(" SANCHKEPKT defined.\n"); +#endif + + return 0; +} + + +/*----------------------------------------------------------- + | Driver entry point (called by ethif_probe2()). + | + | Return: 0 success. + | + | Entry condition: Cpu interrupts ENabled + | (in SPITE of claims to contrary). +*/ +struct net_device * __init oeth_init(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct oeth_private)); + int err; + + if (!dev) return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + PRINTK2("%s:oeth_init\n", dev->name); + + if (oeth_probe(dev) != 0) + { + err = -ENODEV; + goto out; + } + + err = register_netdev(dev); + if (!err) return dev; +out: + free_netdev(dev); + return ERR_PTR(err); +} diff --git a/drivers/net/open_eth.h b/drivers/net/open_eth.h new file mode 100644 index 00000000..de58ada9 --- /dev/null +++ b/drivers/net/open_eth.h @@ -0,0 +1,179 @@ +/*-------------------------------------------------------------------- + * open_eth.c + * + * Ethernet driver for Open Ethernet Controller (www.opencores.org). + * + * Copyright (c) 2002 Simon Srot (simons@opencores.org) + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * History: + * Jun/20/2004 DGT Microtronix Datacom NiosII + * + ---------------------------------------------------------------------*/ + + +/* Ethernet configuration registers */ +typedef struct _oeth_regs { + uint moder; /* Mode Register */ + uint int_src; /* Interrupt Source Register */ + uint int_mask; /* Interrupt Mask Register */ + uint ipgt; /* Back to Bak Inter Packet Gap Register */ + uint ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */ + uint ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */ + uint packet_len; /* Packet Length Register (min. and max.) */ + uint collconf; /* Collision and Retry Configuration Register */ + uint tx_bd_num; /* Transmit Buffer Descriptor Number Register */ + uint ctrlmoder; /* Control Module Mode Register */ + uint miimoder; /* MII Mode Register */ + uint miicommand; /* MII Command Register */ + uint miiaddress; /* MII Address Register */ + uint miitx_data; /* MII Transmit Data Register */ + uint miirx_data; /* MII Receive Data Register */ + uint miistatus; /* MII Status Register */ + uint mac_addr0; /* MAC Individual Address Register 0 */ + uint mac_addr1; /* MAC Individual Address Register 1 */ + uint hash_addr0; /* Hash Register 0 */ + uint hash_addr1; /* Hash Register 1 */ +} oeth_regs; + +/* Ethernet buffer descriptor */ +typedef struct _oeth_bd { +#if 0 + ushort len; /* Buffer length */ + ushort status; /* Buffer status */ +#else + uint len_status; +#endif + uint addr; /* Buffer address */ +} oeth_bd; + +#define OETH_REG_BASE ETH_BASE_ADD +#define OETH_BD_BASE (ETH_BASE_ADD + 0x400) +#define OETH_TOTAL_BD 128 +#define OETH_MAXBUF_LEN 0x600 + +/* Tx BD */ +#define OETH_TX_BD_READY 0x8000 /* Tx BD Ready */ +#define OETH_TX_BD_IRQ 0x4000 /* Tx BD IRQ Enable */ +#define OETH_TX_BD_WRAP 0x2000 /* Tx BD Wrap (last BD) */ +#define OETH_TX_BD_PAD 0x1000 /* Tx BD Pad Enable */ +#define OETH_TX_BD_CRC 0x0800 /* Tx BD CRC Enable */ + +#define OETH_TX_BD_UNDERRUN 0x0100 /* Tx BD Underrun Status */ +#define OETH_TX_BD_RETRY 0x00F0 /* Tx BD Retry Status */ +#define OETH_TX_BD_RETLIM 0x0008 /* Tx BD Retransmission Limit Status */ +#define OETH_TX_BD_LATECOL 0x0004 /* Tx BD Late Collision Status */ +#define OETH_TX_BD_DEFER 0x0002 /* Tx BD Defer Status */ +#define OETH_TX_BD_CARRIER 0x0001 /* Tx BD Carrier Sense Lost Status */ +#define OETH_TX_BD_STATS (OETH_TX_BD_UNDERRUN | \ + OETH_TX_BD_RETRY | \ + OETH_TX_BD_RETLIM | \ + OETH_TX_BD_LATECOL | \ + OETH_TX_BD_DEFER | \ + OETH_TX_BD_CARRIER) + +/* Rx BD */ +#define OETH_RX_BD_EMPTY 0x8000 /* Rx BD Empty */ +#define OETH_RX_BD_IRQ 0x4000 /* Rx BD IRQ Enable */ +#define OETH_RX_BD_WRAP 0x2000 /* Rx BD Wrap (last BD) */ + +#define OETH_RX_BD_MISS 0x0080 /* Rx BD Miss Status */ +#define OETH_RX_BD_OVERRUN 0x0040 /* Rx BD Overrun Status */ +#define OETH_RX_BD_INVSIMB 0x0020 /* Rx BD Invalid Symbol Status */ +#define OETH_RX_BD_DRIBBLE 0x0010 /* Rx BD Dribble Nibble Status */ +#define OETH_RX_BD_TOOLONG 0x0008 /* Rx BD Too Long Status */ +#define OETH_RX_BD_SHORT 0x0004 /* Rx BD Too Short Frame Status */ +#define OETH_RX_BD_CRCERR 0x0002 /* Rx BD CRC Error Status */ +#define OETH_RX_BD_LATECOL 0x0001 /* Rx BD Late Collision Status */ +#define OETH_RX_BD_STATS (OETH_RX_BD_MISS | \ + OETH_RX_BD_OVERRUN | \ + OETH_RX_BD_INVSIMB | \ + OETH_RX_BD_DRIBBLE | \ + OETH_RX_BD_TOOLONG | \ + OETH_RX_BD_SHORT | \ + OETH_RX_BD_CRCERR | \ + OETH_RX_BD_LATECOL) + +/* MODER Register */ +#define OETH_MODER_RXEN 0x00000001 /* Receive Enable */ +#define OETH_MODER_TXEN 0x00000002 /* Transmit Enable */ +#define OETH_MODER_NOPRE 0x00000004 /* No Preamble */ +#define OETH_MODER_BRO 0x00000008 /* Reject Broadcast */ +#define OETH_MODER_IAM 0x00000010 /* Use Individual Hash */ +#define OETH_MODER_PRO 0x00000020 /* Promiscuous (receive all) */ +#define OETH_MODER_IFG 0x00000040 /* Min. IFG not required */ +#define OETH_MODER_LOOPBCK 0x00000080 /* Loop Back */ +#define OETH_MODER_NOBCKOF 0x00000100 /* No Backoff */ +#define OETH_MODER_EXDFREN 0x00000200 /* Excess Defer */ +#define OETH_MODER_FULLD 0x00000400 /* Full Duplex */ +#define OETH_MODER_RST 0x00000800 /* Reset MAC */ +#define OETH_MODER_DLYCRCEN 0x00001000 /* Delayed CRC Enable */ +#define OETH_MODER_CRCEN 0x00002000 /* CRC Enable */ +#define OETH_MODER_HUGEN 0x00004000 /* Huge Enable */ +#define OETH_MODER_PAD 0x00008000 /* Pad Enable */ +#define OETH_MODER_RECSMALL 0x00010000 /* Receive Small */ + +/* Interrupt Source Register */ +#define OETH_INT_TXB 0x00000001 /* Transmit Buffer IRQ */ +#define OETH_INT_TXE 0x00000002 /* Transmit Error IRQ */ +#define OETH_INT_RXF 0x00000004 /* Receive Frame IRQ */ +#define OETH_INT_RXE 0x00000008 /* Receive Error IRQ */ +#define OETH_INT_BUSY 0x00000010 /* Busy IRQ */ +#define OETH_INT_TXC 0x00000020 /* Transmit Control Frame IRQ */ +#define OETH_INT_RXC 0x00000040 /* Received Control Frame IRQ */ + +/* Interrupt Mask Register */ +#define OETH_INT_MASK_TXB 0x00000001 /* Transmit Buffer IRQ Mask */ +#define OETH_INT_MASK_TXE 0x00000002 /* Transmit Error IRQ Mask */ +#define OETH_INT_MASK_RXF 0x00000004 /* Receive Frame IRQ Mask */ +#define OETH_INT_MASK_RXE 0x00000008 /* Receive Error IRQ Mask */ +#define OETH_INT_MASK_BUSY 0x00000010 /* Busy IRQ Mask */ +#define OETH_INT_MASK_TXC 0x00000020 /* Transmit Control Frame IRQ Mask */ +#define OETH_INT_MASK_RXC 0x00000040 /* Received Control Frame IRQ Mask */ + +/* Control Module Mode Register */ +#define OETH_CTRLMODER_PASSALL 0x00000001 /* Pass Control Frames */ +#define OETH_CTRLMODER_RXFLOW 0x00000002 /* Receive Control Flow Enable */ +#define OETH_CTRLMODER_TXFLOW 0x00000004 /* Transmit Control Flow Enable */ + +/* MII Mode Register */ +#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */ +#define OETH_MIIMODER_NOPRE 0x00000100 /* No Preamble */ +#define OETH_MIIMODER_RST 0x00000200 /* MIIM Reset */ + +/* MII Command Register */ +#define OETH_MIICOMMAND_SCANSTAT 0x00000001 /* Scan Status */ +#define OETH_MIICOMMAND_RSTAT 0x00000002 /* Read Status */ +#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */ + +/* MII Address Register */ +#define OETH_MIIADDRESS_FIAD 0x0000001F /* PHY Address */ + //;dgt;May2005-note Mx Altera Nios (CONFIG_EXCALIBUR) with + //; a TDK78Q2120 phy does NOT use OETH_MIIADDRESS_FIAD, but + //; instead uses its own PHY_ADDRESS (0x00 = "broadcast" + //; phy address) invention + //;dgt:IIRC, Mx Tdk's USED to use address 0x1F but changed some + //; undocumented time ago... +#define OETH_MIIADDRESS_RGAD 0x00001F00 /* RGAD Address */ + +/* MII Status Register */ +#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */ +#define OETH_MIISTATUS_BUSY 0x00000002 /* MII Busy */ +#define OETH_MIISTATUS_NVALID 0x00000004 /* Data in MII Status Register is invalid */ + +/*----------------------------------------------------------------------*/ + + #define OETH_IO_EXTENT (sizeof(oeth_regs)) + +/*----------------------------------------------------------------------*/ diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b977ed85..8676fc87 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -65,6 +65,9 @@ VERSION 2.2LK <2005/01/25> #include #include #include +#ifdef CONFIG_LEDMAN +#include +#endif #include #include @@ -531,8 +534,9 @@ static int mdio_read(void __iomem *ioaddr, int RegAddr) static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) { RTL_W16(IntrMask, 0x0000); - +#if 0 RTL_W16(IntrStatus, 0xffff); +#endif } static void rtl8169_asic_down(void __iomem *ioaddr) @@ -1797,12 +1801,25 @@ static void rtl8169_hw_reset(void __iomem *ioaddr) RTL_R8(ChipCmd); } -static void -rtl8169_hw_start(struct net_device *dev) +static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + u32 cfg = rtl8169_rx_config; + + cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + RTL_W32(RxConfig, cfg); + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); +} + +static void rtl8169_hw_start(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; + u16 cmd; u32 i; /* Soft reset the chip. */ @@ -1815,6 +1832,11 @@ rtl8169_hw_start(struct net_device *dev) msleep_interruptible(1); } + if (tp->mac_version == RTL_GIGA_MAC_VER_05) { + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08); + } + if (tp->mac_version == RTL_GIGA_MAC_VER_13) { pci_write_config_word(pdev, 0x68, 0x00); pci_write_config_word(pdev, 0x69, 0x08); @@ -1822,8 +1844,6 @@ rtl8169_hw_start(struct net_device *dev) /* Undocumented stuff. */ if (tp->mac_version == RTL_GIGA_MAC_VER_05) { - u16 cmd; - /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */ if ((RTL_R8(Config2) & 0x07) & 0x01) RTL_W32(0x7c, 0x0007ffff); @@ -1835,23 +1855,32 @@ rtl8169_hw_start(struct net_device *dev) pci_write_config_word(pdev, PCI_COMMAND, cmd); } - RTL_W8(Cfg9346, Cfg9346_Unlock); + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + RTL_W8(EarlyTxThres, EarlyTxThld); + /* Restore our idea of the MAC address */ + for (i = 0; i < MAC_ADDR_LEN; i++) + RTL_W8(MAC0 + i, dev->dev_addr[i]); + /* Low hurts. Let's disable the filtering. */ RTL_W16(RxMaxSize, 16383); - /* Set Rx Config register */ - i = rtl8169_rx_config | - (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); - RTL_W32(RxConfig, i); + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + rtl8169_set_rx_tx_config_registers(tp); - /* Set DMA burst size and Interframe Gap Time */ - RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | - (InterFrameGap << TxInterFrameGapShift)); + cmd = RTL_R16(CPlusCmd); + RTL_W16(CPlusCmd, cmd); - tp->cp_cmd |= RTL_R16(CPlusCmd) | PCIMulRW; + tp->cp_cmd |= cmd | PCIMulRW; if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || (tp->mac_version == RTL_GIGA_MAC_VER_03)) { @@ -1877,7 +1906,15 @@ rtl8169_hw_start(struct net_device *dev) RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK)); RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32)); RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK)); - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && + (tp->mac_version != RTL_GIGA_MAC_VER_02) && + (tp->mac_version != RTL_GIGA_MAC_VER_03) && + (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl8169_set_rx_tx_config_registers(tp); + } + RTL_W8(Cfg9346, Cfg9346_Lock); /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ @@ -2243,6 +2280,13 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 status, len; u32 opts1; int ret = NETDEV_TX_OK; + +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (dev->name[3] == '0') ? LEDMAN_LAN1_TX : + (dev->name[3] == '1') ? LEDMAN_LAN2_TX : + LEDMAN_LAN3_TX); +#endif if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { if (netif_msg_drv(tp)) { @@ -2459,6 +2503,13 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (dev->name[3] == '0') ? LEDMAN_LAN1_RX : + (dev->name[3] == '1') ? LEDMAN_LAN2_RX : + LEDMAN_LAN3_RX); +#endif + for (; rx_left > 0; rx_left--, cur_rx++) { unsigned int entry = cur_rx % NUM_RX_DESC; struct RxDesc *desc = tp->RxDescArray + entry; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 39c2152a..687fdc74 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -783,6 +783,8 @@ sl_alloc(dev_t line) if (dev) { sl = netdev_priv(dev); if (test_bit(SLF_INUSE, &sl->flags)) { + printk(KERN_WARNING "%s: netdev in use on open, will fail.\n", + sl->dev->name); unregister_netdevice(dev); dev = NULL; slip_devs[i] = NULL; @@ -934,11 +936,13 @@ static void slip_close(struct tty_struct *tty) { struct slip *sl = (struct slip *) tty->disc_data; + struct net_device *dev = sl->dev; /* First make sure we're connected. */ if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty) return; + rtnl_lock(); tty->disc_data = NULL; sl->tty = NULL; if (!sl->leased) @@ -951,6 +955,17 @@ slip_close(struct tty_struct *tty) #endif /* Count references from TTY module */ + + /* unregister the netdev, otherwise the sysfs workq'd unregister + * causes us to fail with EEXIST when registering on open */ + + if (dev && test_bit(SLF_INUSE, &sl->flags)) { + slip_devs[dev->base_addr] = NULL; + sl->dev = NULL; + unregister_netdevice(dev); + clear_bit(SLF_INUSE, &sl->flags); + } + rtnl_unlock(); } /************************************************************************ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index c0d13d65..45b7a79e 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -59,9 +59,11 @@ static const char version[] = #include #include +#include #include #include #include +#include #include #include #include @@ -78,6 +80,39 @@ static const char version[] = #include "smc9194.h" +#ifdef CONFIG_M68EZ328 +#include +#include +#include +unsigned char smc_defethaddr[] = { 0x00, 0x10, 0x8b, 0xf1, 0xda, 0x01 }; +#define NO_AUTOPROBE +#endif + +#ifdef CONFIG_COLDFIRE +#include +#include +#include + +unsigned char smc_defethaddr[] = { 0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01 }; + +#define NO_AUTOPROBE +#endif + +#ifdef CONFIG_SH_KEYWEST +#include +#define NO_AUTOPROBE +#define PHY_SETUP +#endif + +#ifdef CONFIG_LEDMAN +#include +#endif + +#if defined(CONFIG_CPU_H8300H) || defined(CONFIG_CPU_H8S) +#include +#define NO_AUTOPROBE +#endif + #define DRV_NAME "smc9194" /*------------------------------------------------------------------------ @@ -90,7 +125,8 @@ static const char version[] = . Do you want to use 32 bit xfers? This should work on all chips, as . the chipset is designed to accommodate them. */ -#ifdef __sh__ +#if (defined(__sh__) && !defined(CONFIG_SH_KEYWEST)) || \ + defined(__H8300H__) || defined(__H8300S__) #undef USE_32_BIT #else #define USE_32_BIT 1 @@ -105,17 +141,37 @@ static const char version[] = #endif /* + .A typedef so we can change what IO looks like easily +*/ +typedef unsigned int smcio_t; + +/* .the SMC9194 can be at any of the following port addresses. To change, .for a slightly different card, you can add it to the array. Keep in .mind that the array must end in zero. */ +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) || \ + defined(CONFIG_SH_KEYWEST) + +#ifdef CONFIG_NETtel +static smcio_t smc_portlist[] = { 0x30600300, 0x30600000, 0 }; +static unsigned int smc_irqlist[] = { 29, 27, 0 }; +#elif defined(CONFIG_SH_KEYWEST) +static smcio_t smc_portlist[] = { KEYWEST_ETHR, 0 }; +static unsigned int smc_irqlist[] = { IRQ4_IRQ, 0 }; +#elif defined(CONFIG_M68EZ328) +/* make sure that you program Port D selects to allow the interrupts! */ +static smcio_t smc_portlist[] = { 0x2000300, 0x2000320, 0 }; +static unsigned int smc_irqlist[] = { IRQ1_IRQ_NUM, IRQ2_IRQ_NUM, 0 }; +#elif defined(CONFIG_CLEOPATRA) +static unsigned int smc_portlist[] = { 0x30600300, 0 }; +static unsigned int smc_irqlist[] = { 29, 0 }; +#else +static smcio_t smc_portlist[] = { 0x30600300, 0 }; +static unsigned int smc_irqlist[] = { 27, 0 }; +#endif -struct devlist { - unsigned int port; - unsigned int irq; -}; - -#if defined(CONFIG_H8S_EDOSK2674) +#elif defined(CONFIG_H8S_EDOSK2674) static struct devlist smc_devlist[] __initdata = { {.port = 0xf80000, .irq = 16}, {.port = 0, .irq = 0 }, @@ -294,7 +350,7 @@ static inline void smc_tx( struct net_device * dev ); . Test if a given location contains a chip, trying to cause as . little damage as possible if it's not a SMC chip. */ -static int smc_probe(struct net_device *dev, int ioaddr); +static int smc_probe(struct net_device *dev, smcio_t ioaddr); /* . A rather simple routine to print out a packet for debugging purposes. @@ -315,20 +371,31 @@ static void smc_hardware_send_packet( struct net_device * dev ); static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); /* this does a soft reset on the device */ -static void smc_reset( int ioaddr ); +static void smc_reset( smcio_t ioaddr ); /* Enable Interrupts, Receive, and Transmit */ -static void smc_enable( int ioaddr ); +static void smc_enable( smcio_t ioaddr ); /* this puts the device in an inactive state */ -static void smc_shutdown( int ioaddr ); +static void smc_shutdown( smcio_t ioaddr ); +#ifndef NO_AUTOPROBE /* This routine will find the IRQ of the driver if one is not . specified in the input to the device. */ -static int smc_findirq( int ioaddr ); +static int smc_findirq( smcio_t ioaddr ); +#endif + +#ifdef PHY_SETUP +static void clkmdio(smcio_t ioaddr, unsigned int MGMTData); +static unsigned PHYAccess(smcio_t ioaddr, unsigned char PHYAdd, + unsigned char RegAdd, unsigned char OPCode, unsigned wData); +static unsigned char DetectPHY(smcio_t ioaddr, unsigned long *OUI, + unsigned char *Model, unsigned char *Revision); +static int setup_phy(smcio_t ioaddr); +#endif /* - . Function: smc_reset( int ioaddr ) + . Function: smc_reset( smcio_t ioaddr ) . Purpose: . This sets the SMC91xx chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. @@ -344,7 +411,7 @@ static int smc_findirq( int ioaddr ); . 5. clear all interrupts . */ -static void smc_reset( int ioaddr ) +static void smc_reset( smcio_t ioaddr ) { /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ @@ -365,6 +432,10 @@ static void smc_reset( int ioaddr ) SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); +#if defined(CONFIG_LEDMAN) && defined(CONFIG_SNAPGEAR) + outw( inw( ioaddr + CONTROL ) | CTL_LE_ENABLE , ioaddr + CONTROL ); +#endif + /* Reset the MMU */ SMC_SELECT_BANK( 2 ); outw( MC_RESET, ioaddr + MMU_CMD ); @@ -373,7 +444,7 @@ static void smc_reset( int ioaddr ) but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT( 0 ); } /* @@ -384,7 +455,7 @@ static void smc_reset( int ioaddr ) . 2. Enable the receiver . 3. Enable interrupts */ -static void smc_enable( int ioaddr ) +static void smc_enable( smcio_t ioaddr ) { SMC_SELECT_BANK( 0 ); /* see the header file for options in TCR/RCR NORMAL*/ @@ -393,7 +464,7 @@ static void smc_enable( int ioaddr ) /* now, enable interrupts */ SMC_SELECT_BANK( 2 ); - outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); + SMC_SET_INT( SMC_INTERRUPT_MASK ); } /* @@ -410,16 +481,21 @@ static void smc_enable( int ioaddr ) . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working. */ -static void smc_shutdown( int ioaddr ) +static void smc_shutdown( smcio_t ioaddr ) { /* no more interrupts for me */ SMC_SELECT_BANK( 2 ); - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT( 0 ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( 0 ); +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outw( RCR_CLEAR, ioaddr + RCR ); + outw( TCR_CLEAR, ioaddr + TCR ); +#else outb( RCR_CLEAR, ioaddr + RCR ); outb( TCR_CLEAR, ioaddr + TCR ); +#endif /* CONFIG_COLDFIRE */ #if 0 /* finally, shut the chip down */ SMC_SELECT_BANK( 1 ); @@ -429,7 +505,7 @@ static void smc_shutdown( int ioaddr ) /* - . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) + . Function: smc_setmulticast( smcio_t ioaddr, int count, dev_mc_list * adds ) . Purpose: . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. @@ -446,7 +522,7 @@ static void smc_shutdown( int ioaddr ) */ -static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { +static void smc_setmulticast( smcio_t ioaddr, int count, struct dev_mc_list * addrs ) { int i; unsigned char multicast_table[ 8 ]; struct dev_mc_list * cur_addr; @@ -479,11 +555,18 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs /* now, the table can be loaded into the chipset */ SMC_SELECT_BANK( 3 ); +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + for ( i = 0; i < 8 ; i += 2 ) { + outw(((multicast_table[i+1]<<8)+(multicast_table[i])), ioaddr+MULTICAST1+i ); + } +#else for ( i = 0; i < 8 ; i++ ) { outb( multicast_table[i], ioaddr + MULTICAST1 + i ); } +#endif } + /* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) . Purpose: @@ -574,7 +657,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de status = inb( ioaddr + INTERRUPT ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ - outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); + SMC_ACK_INT( IM_ALLOC_INT ); break; } } while ( -- time_out ); @@ -616,7 +699,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; - unsigned int ioaddr; + smcio_t ioaddr; byte * buf; ioaddr = dev->base_addr; @@ -640,7 +723,11 @@ static void smc_hardware_send_packet( struct net_device * dev ) } /* we have a packet address, so tell the card to use it */ +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outw( packet_no, ioaddr + PNR_ARR ); +#else outb( packet_no, ioaddr + PNR_ARR ); +#endif /* point to the beginning of the packet */ outw( PTR_AUTOINC , ioaddr + POINTER ); @@ -652,14 +739,23 @@ static void smc_hardware_send_packet( struct net_device * dev ) /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */ + #ifdef USE_32_BIT +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outl( (length +6 ) , ioaddr + DATA_1 ); +#else outl( (length +6 ) << 16 , ioaddr + DATA_1 ); +#endif #else outw( 0, ioaddr + DATA_1 ); /* send the packet length ( +6 for status words, length, and ctl*/ +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) || defined(CONFIG_CPU_H8S) + outw( (length+6) & 0xFFFF, ioaddr + DATA_1 ); +#else outb( (length+6) & 0xFF,ioaddr + DATA_1 ); outb( (length+6) >> 8 , ioaddr + DATA_1 ); #endif +#endif /* send the actual data . I _think_ it's faster to send the longs first, and then @@ -671,7 +767,9 @@ static void smc_hardware_send_packet( struct net_device * dev ) #ifdef USE_32_BIT if ( length & 0x2 ) { outsl(ioaddr + DATA_1, buf, length >> 2 ); -#if !defined(__H8300H__) && !defined(__H8300S__) +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outwd( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); +#elif !defined(__H8300H__) && !defined(__H8300S__) outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); #else ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); @@ -687,8 +785,12 @@ static void smc_hardware_send_packet( struct net_device * dev ) if ( (length & 1) == 0 ) { outw( 0, ioaddr + DATA_1 ); } else { +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outw( buf[length -1 ] | (0x20 << 8), ioaddr + DATA_1); +#else outb( buf[length -1 ], ioaddr + DATA_1 ); outb( 0x20, ioaddr + DATA_1); +#endif } /* enable the interrupts */ @@ -751,8 +853,11 @@ struct net_device * __init smc_init(int unit) } else if (io != 0) { /* Don't probe at all. */ err = -ENXIO; } else { - for (;smcdev->port; smcdev++) { - if (smc_probe(dev, smcdev->port) == 0) + for (port = smc_portlist; *port; port++) { +#ifdef CONFIG_NETtel + smc_remap(port); +#endif + if (smc_probe(dev, *port) == 0) break; } if (!smcdev->port) @@ -779,13 +884,21 @@ out: . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ -int __init smc_findirq( int ioaddr ) +#ifndef NO_AUTOPROBE +int __init smc_findirq( smcio_t ioaddr ) { #ifndef NO_AUTOPROBE int timeout = 20; unsigned long cookie; +#if 0 + /* I have to do a STI() here, because this is called from + a routine that does an CLI during this process, making it + rather difficult to get interrupts for auto detection */ + sti(); +#endif + cookie = probe_irq_on(); /* @@ -797,7 +910,7 @@ int __init smc_findirq( int ioaddr ) SMC_SELECT_BANK(2); /* enable ALLOCation interrupts ONLY */ - outb( IM_ALLOC_INT, ioaddr + INT_MASK ); + SMC_SET_INT( IM_ALLOC_INT ); /* . Allocate 512 bytes of memory. Note that the chip was just @@ -832,7 +945,13 @@ int __init smc_findirq( int ioaddr ) SMC_DELAY(); /* and disable all interrupts again */ - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT( 0 ); + +#if 0 + /* clear hardware interrupts again, because that's how it + was when I was called... */ + cli(); +#endif /* and return what I found */ return probe_irq_off(cookie); @@ -845,9 +964,10 @@ int __init smc_findirq( int ioaddr ) return 0; #endif } +#endif /* NO_AUTOPROBE */ /*---------------------------------------------------------------------- - . Function: smc_probe( int ioaddr ) + . Function: smc_probe( smcio_t ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC9xxx chip. @@ -875,11 +995,17 @@ int __init smc_findirq( int ioaddr ) . o GRAB the region .----------------------------------------------------------------- */ -static int __init smc_probe(struct net_device *dev, int ioaddr) +static int __init smc_probe(struct net_device *dev, smcio_t ioaddr) { int i, memory, retval; static unsigned version_printed; unsigned int bank; +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || defined(CONFIG_DISKtel) || defined(CONFIG_CLEOPATRA) + static int nr = 0; +#endif +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + unsigned char *ep; +#endif const char *version_string; const char *if_string; @@ -891,9 +1017,18 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) word memory_info_register; word memory_cfg_register; +#if !defined(CONFIG_COLDFIRE) && !defined(CONFIG_M68EZ328) && \ + !defined(CONFIG_CPU_H8300H) && !defined(CONFIG_CPU_H8S) /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; +#elif defined(CONFIG_COLDFIRE) + /* + * We need to put the SMC into 68k mode. + * Do a write before anything else. + */ + outw(0, ioaddr + BANK_SELECT); +#endif dev->irq = irq; dev->if_port = ifport; @@ -912,13 +1047,13 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) retval = -ENODEV; goto err_out; } -#if !defined(CONFIG_H8S_EDOSK2674) /* well, we've already written once, so hopefully another time won't hurt. This time, I need to switch the bank register to bank 1, so I can access the base address register */ +#if !defined(CONFIG_CPU_H8300H) && !defined(CONFIG_CPU_H8S) SMC_SELECT_BANK(1); base_address_register = inw( ioaddr + BASE ); - if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { + if ( (ioaddr & 0x3E0) != ( base_address_register >> 3 & 0x3E0 ) ) { printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)." "Probably not a SMC chip\n", ioaddr, base_address_register >> 3 & 0x3E0 ); @@ -931,7 +1066,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) (void)base_address_register; /* Warning suppression */ #endif - /* check if the revision register is something that I recognize. These might need to be added to later, as future revisions could be added. */ @@ -949,13 +1083,30 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) /* at this point I'll assume that the chip is an SMC9xxx. It might be prudent to check a listing of MAC addresses against the hardware address, or do some other tests. */ - if (version_printed++ == 0) printk("%s", version); /* fill in some of the fields */ dev->base_addr = ioaddr; +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || defined(CONFIG_DISKtel) || defined(CONFIG_CLEOPATRA) + /* + . MAC address should be in FLASH, check that it is valid. + . If good use it, otherwise use the default. + */ + ep = (unsigned char *) (0xf0006000 + (nr++ * 6)); + if ((ep[0] == 0xff) && (ep[1] == 0xff) && (ep[2] == 0xff) && + (ep[3] == 0xff) && (ep[4] == 0xff) && (ep[5] == 0xff)) + ep = (unsigned char *) &smc_defethaddr[0]; + else if ((ep[0] == 0) && (ep[1] == 0) && (ep[2] == 0) && + (ep[3] == 0) && (ep[4] == 0) && (ep[5] == 0)) + ep = (unsigned char *) &smc_defethaddr[0]; +#else + ep = (unsigned char *) &smc_defethaddr[0]; +#endif +#endif + /* . Get the MAC address ( bank 1, regs 4 - 9 ) */ @@ -963,11 +1114,23 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) for ( i = 0; i < 6; i += 2 ) { word address; +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + dev->dev_addr[ i ] = ep[ i ]; + dev->dev_addr[ i + 1 ] = ep[ i + 1 ]; + address = (((word) ep[ i ]) << 8) | ep[ i + 1 ]; + outw( address, ioaddr + ADDR0 + i); +#else address = inw( ioaddr + ADDR0 + i ); dev->dev_addr[ i + 1] = address >> 8; - dev->dev_addr[ i ] = address & 0xFF; + dev->dev_addr[ i ] = address & 0xFF; +#endif } +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + /* HACK: to support 2 ethernets when using default address! */ + smc_defethaddr[5]++; +#endif + /* get the memory information */ SMC_SELECT_BANK( 0 ); @@ -1020,6 +1183,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) . what (s)he is doing. No checking is done!!!! . */ +#ifndef NO_AUTOPROBE if ( dev->irq < 2 ) { int trials; @@ -1037,6 +1201,13 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) retval = -ENODEV; goto err_out; } +#else + if (dev->irq == 0 ) { + printk(CARDNAME + ": Autoprobing IRQs is not supported for this configuration.\n"); + return -ENODEV; + } +#endif /* now, print out the card info, in a short format.. */ @@ -1055,12 +1226,21 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) memset(dev->priv, 0, sizeof(struct smc_local)); /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); - if (retval) { - printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME, +#ifdef CONFIG_COLDFIRE + mcf_autovector(dev->irq); + retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); +#elif defined(CONFIG_M68EZ328) && !defined(CONFIG_CWEZ328) && !defined(CONFIG_CWVZ328) + retval = request_irq(IRQ_MACHSPEC | dev->irq, &smc_interrupt, + IRQ_FLG_STD, dev->name, dev); + if (retval) panic("Unable to attach Lan91C96 intr\n"); +#else + retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); +#endif + if (retval) { + printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); goto err_out; - } + } dev->open = smc_open; dev->stop = smc_close; @@ -1070,6 +1250,9 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; +#ifdef PHY_SETUP + setup_phy( ioaddr ); +#endif return 0; err_out: @@ -1122,7 +1305,7 @@ static void print_packet( byte * buf, int length ) */ static int smc_open(struct net_device *dev) { - int ioaddr = dev->base_addr; + smcio_t ioaddr = dev->base_addr; int i; /* used to set hw ethernet address */ @@ -1137,6 +1320,11 @@ static int smc_open(struct net_device *dev) /* Select which interface to use */ SMC_SELECT_BANK( 1 ); +#if defined(CONFIG_DISKtel) || defined(CONFIG_SH_KEYWEST) + /* Setup to use external PHY on smc91c110 */ + outw( inw( ioaddr + CONFIG ) | CFG_NO_WAIT | CFG_MII_SELECT, + (ioaddr + CONFIG )); +#else if ( dev->if_port == 1 ) { outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, ioaddr + CONFIG ); @@ -1145,6 +1333,7 @@ static int smc_open(struct net_device *dev) outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, ioaddr + CONFIG ); } +#endif /* According to Becker, I have to set the hardware address @@ -1161,6 +1350,18 @@ static int smc_open(struct net_device *dev) } netif_start_queue(dev); + +#if defined(CONFIG_LEDMAN) && defined(CONFIG_SNAPGEAR) + /* + * fix the link status LED's + */ + SMC_SELECT_BANK( 0 ); + ledman_cmd((inw(ioaddr + EPH_STATUS) & ES_LINK_OK) == ES_LINK_OK ? + LEDMAN_CMD_ON : LEDMAN_CMD_OFF, + strcmp(dev->name, "eth0") ? + LEDMAN_LAN2_LINK : LEDMAN_LAN1_LINK); +#endif + return 0; } @@ -1202,10 +1403,9 @@ static void smc_timeout(struct net_device *dev) static void smc_rcv(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int packet_number; - word status; - word packet_length; + int ioaddr = dev->base_addr; + int packet_number; + word status, packet_length; /* assume bank 2 */ @@ -1222,8 +1422,16 @@ static void smc_rcv(struct net_device *dev) outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); /* First two words are status and packet_length */ +#ifndef CONFIG_SH_KEYWEST status = inw( ioaddr + DATA_1 ); packet_length = inw( ioaddr + DATA_1 ); +#else + { + unsigned int l = inl( ioaddr + DATA_1 ); + status = l & 0xffff; + packet_length = l >> 16; + } +#endif packet_length &= 0x07ff; /* mask off top bits */ @@ -1274,9 +1482,17 @@ static void smc_rcv(struct net_device *dev) packet_length >> 2, packet_length & 3 )); insl(ioaddr + DATA_1 , data, packet_length >> 2 ); /* read the left over bytes */ +#ifndef CONFIG_SH_KEYWEST insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC), packet_length & 0x3 ); #else + if (packet_length & 3) { + union { unsigned int l; char data[4]; } l; + l.l = inl(ioaddr + DATA_1); + memcpy(data + (packet_length & ~0x3), l.data, packet_length & 0x3); + } +#endif +#else PRINTK3((" Reading %d words and %d byte(s) \n", (packet_length >> 1 ), packet_length & 1 )); insw(ioaddr + DATA_1 , data, packet_length >> 1); @@ -1327,7 +1543,7 @@ done: ************************************************************************/ static void smc_tx( struct net_device * dev ) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; struct smc_local *lp = netdev_priv(dev); byte saved_packet; byte packet_no; @@ -1341,7 +1557,12 @@ static void smc_tx( struct net_device * dev ) packet_no &= 0x7F; /* select this as the packet to read from */ - outb( packet_no, ioaddr + PNR_ARR ); +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outw( packet_no, ioaddr + PNR_ARR ); +#else + outb( packet_no, ioaddr + PNR_ARR ); +#endif + /* read the first word from this packet */ outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); @@ -1352,8 +1573,10 @@ static void smc_tx( struct net_device * dev ) lp->stats.tx_errors++; if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; if ( tx_status & TS_LATCOL ) { +#if 0 printk(KERN_DEBUG CARDNAME ": Late collision occurred on last xmit.\n"); +#endif lp->stats.tx_window_errors++; } #if 0 @@ -1374,7 +1597,11 @@ static void smc_tx( struct net_device * dev ) /* one less packet waiting for me */ lp->packets_waiting--; +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + outw( saved_packet, ioaddr + PNR_ARR ); +#else outb( saved_packet, ioaddr + PNR_ARR ); +#endif return; } @@ -1520,6 +1747,11 @@ static int smc_close(struct net_device *dev) /* clear everything */ smc_shutdown( dev->base_addr ); +#if defined(CONFIG_LEDMAN) && defined(CONFIG_SNAPGEAR) + ledman_cmd(LEDMAN_CMD_OFF, + strcmp(dev->name, "eth0")?LEDMAN_LAN2_LINK : LEDMAN_LAN1_LINK); +#endif + /* Update the statistics here. */ return 0; } @@ -1544,7 +1776,7 @@ static struct net_device_stats* smc_query_statistics(struct net_device *dev) { */ static void smc_set_multicast_list(struct net_device *dev) { - short ioaddr = dev->base_addr; + smcio_t ioaddr = dev->base_addr; SMC_SELECT_BANK(0); if ( dev->flags & IFF_PROMISC ) @@ -1591,6 +1823,12 @@ static void smc_set_multicast_list(struct net_device *dev) } } +#ifdef PHY_SETUP +static int phy_delay1 = 4; +static int phy_delay2 = 1; +static int phy_delay3 = 100; +#endif + #ifdef MODULE static struct net_device *devSMC9194; @@ -1603,12 +1841,25 @@ MODULE_PARM_DESC(io, "SMC 99194 I/O base address"); MODULE_PARM_DESC(irq, "SMC 99194 IRQ number"); MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)"); +#ifdef PHY_SETUP +MODULE_PARM(phy_delay1, "i"); +MODULE_PARM(phy_delay2, "i"); +MODULE_PARM(phy_delay3, "i"); +MODULE_PARM_DESC(phy_delay1, "Per MII clock delay [4]"); +MODULE_PARM_DESC(phy_delay2, "General delay [1]"); +MODULE_PARM_DESC(phy_delay3, "pre probe delay [100]"); +#endif + int __init init_module(void) { if (io == 0) printk(KERN_WARNING CARDNAME": You shouldn't use auto-probing with insmod!\n" ); +#ifdef PHY_SETUP + printk(CARDNAME ": phy_delays %d %d %d\n", phy_delay1, phy_delay2, + phy_delay3); +#endif /* copy the parameters from insmod into the device structure */ devSMC9194 = smc_init(-1); if (IS_ERR(devSMC9194)) @@ -1625,3 +1876,437 @@ void cleanup_module(void) } #endif /* MODULE */ + + +#ifdef PHY_SETUP +/*----------------------------------------------------------- + . PHY/MII setup routines + . +*/ + +#define phy_delay(x) ({ int d; for (d = 0; d < 100; d++) udelay((x) * 10); }) + +/* + * Ports for talking to the PHY/MII + */ + +#define NV_CONTROL 0x10 +#define MIICTRL 0x30 +#define MIIDATA 0x34 +#define MIICFG 0x38 + +#define MIIREAD 0x0001 +#define MIIWRITE 0x0002 + +#define MDO 0x01 /* MII Register bits */ +#define MDI 0x02 +#define MCLK 0x04 +#define MDOE 0x08 +#define MALL 0x0F +#define OPWrite 0x01 +#define OPRead 0x02 + + +#define PHY_CR 0 /* PHY Registers and bits */ +#define PHY_CR_Reset 0x8000 +#define PHY_CR_Speed 0x2000 +#define PHY_CR_Duplex 0x0100 + +#define PHY_SR 1 +#define PHY_ID1 2 +#define PHY_ID2 3 + +/* + * PHY propietary registers + */ + +#define PHY_NATIONAL_PAR 0x19 +#define PHY_NATIONAL_PAR_DUPLEX 0x0080 +#define PHY_NATIONAL_PAR_SPEED_10 0x0040 + +#define PHY_TDK_DIAG 0x12 +#define PHY_TDK_DIAG_DUPLEX 0x0800 +#define PHY_TDK_DIAG_RATE 0x0400 + +#define PHY_QSI_BASETX 0x1F +#define PHY_QSI_BASETX_OPMODE_MASK 0x001c +#define PHY_QSI_BASETX_OPMODE_10HD (2<<0x1) +#define PHY_QSI_BASETX_OPMODE_100HD (2<<0x2) +#define PHY_QSI_BASETX_OPMODE_10FD (2<<0x5) +#define PHY_QSI_BASETX_OPMODE_100FD (2<<0x6) + +#define PHY_SEEQ_STATUS_OUTPUT 0x12 +#define PHY_SEEQ_SPD_DET 0x80 +#define PHY_SEEQ_DPLX_DET 0x40 + +#define PHY_OUI_QSI 0x006051 +#define PHY_OUI_TDK 0x00C039 +#define PHY_OUI_MITELSMSC 0x00A087 +#define PHY_OUI_NATIONAL 0x080017 +#define PHY_OUI_SEEQSMSC 0x0005BE + +#define NWAY_TIMEOUT 10 + +#define MAC_IS_FEAST() (1) +#define MAC_IS_EPIC() (0) + +static void +clkmdio(smcio_t ioaddr, unsigned int MGMTData) +{ + outw(MGMTData, ioaddr + MGMT); + udelay(phy_delay1); + outw(MGMTData | MCLK, ioaddr + MGMT); + udelay(phy_delay1); +} + + +static unsigned +PHYAccess( + smcio_t ioaddr, + unsigned char PHYAdd, + unsigned char RegAdd, + unsigned char OPCode, + unsigned wData) +{ + int i; + unsigned MGMTval; + + // Filter unused bits from input variables. + + PHYAdd &= 0x1F; + RegAdd &= 0x1F; + OPCode &= 0x03; + + if (MAC_IS_FEAST()) { + MGMTval = inw(ioaddr + MGMT) & (MALL ^ 0xFFFF); + + // Output Preamble (32 '1's) + + for (i = 0; i < 32; i++) + clkmdio(ioaddr, MGMTval | MDOE | MDO); + + // Output Start of Frame ('01') + + for (i = 0; i < 2; i++) + clkmdio(ioaddr, MGMTval | MDOE | i); + + // Output OPCode ('01' for write or '10' for Read) + + for (i = 1; i >= 0; i--) + clkmdio(ioaddr, MGMTval | MDOE | ((OPCode>>i) & 0x01) ); + + // Output PHY Address + + for (i = 4; i >= 0; i--) + clkmdio(ioaddr, MGMTval | MDOE | ((PHYAdd>>i) & 0x01) ); + + // Output Register Address + + for (i = 4; i >= 0; i--) + clkmdio(ioaddr, MGMTval | MDOE | ((RegAdd>>i) & 0x01) ); + + if (OPCode == OPRead) { + // Read Operation + + // Implement Turnaround ('Z0') + + clkmdio(ioaddr, MGMTval); + // clkmdio(ioaddr, MGMTval | MDOE); + + // Read Data + + wData = 0; + + for (i = 15; i >= 0; i--) { + clkmdio(ioaddr, MGMTval); + wData |= (((inw(ioaddr + MGMT) & MDI) >> 1) << i); + } + + // Add Idle state + + clkmdio(ioaddr, MGMTval); + + return (wData); + } else { + // Write Operation + + // Implement Turnaround ('10') + + for (i = 1; i >= 0; i--) + clkmdio(ioaddr, MGMTval | MDOE | ((2>>i) & 0x01)); + + // Write Data + + for (i = 15; i >= 0; i--) + clkmdio(ioaddr, MGMTval | MDOE | ((wData>>i) & 0x01)); + + // Add Idle state + + clkmdio(ioaddr, MGMTval); + + return (1); + } + } + + if (MAC_IS_EPIC()) { + if (OPCode == OPRead) { + // Read Operation + outw((((unsigned)PHYAdd)<<9) | (((unsigned)RegAdd)<<4) | MIIREAD, + ioaddr + MIICTRL); + phy_delay(phy_delay2); + wData = inw(MIIDATA); + return(wData); + } else { + // Write Operation + outw(wData, ioaddr + MIIDATA); + outw((((unsigned)PHYAdd)<<9) | (((unsigned)RegAdd)<<4) | MIIWRITE, + ioaddr + MIICTRL); + phy_delay(phy_delay2); + return(1); + } + } + + return(1); + +} + + +static unsigned char +DetectPHY( + smcio_t ioaddr, + unsigned long *OUI, + unsigned char *Model, + unsigned char *Revision) +{ + unsigned int PhyId1, PhyId2; + unsigned char PhyAdd=0xff; + int Count; + + for (Count=31; Count >= 0; Count--) { + PhyId1 = PHYAccess(ioaddr, Count, PHY_ID1, OPRead, 0); + PhyId1 = PHYAccess(ioaddr, Count, PHY_ID1, OPRead, 0); + PhyId2 = PHYAccess(ioaddr, Count, PHY_ID2, OPRead, 0); + PhyId2 = PHYAccess(ioaddr, Count, PHY_ID2, OPRead, 0); + + if (PhyId1 > 0x0000 && PhyId1 < 0xffff && PhyId2 > 0x0000 && + PhyId2 < 0xffff && PhyId1 != 0x8000 && PhyId2 != 0x8000) { + PhyAdd = (unsigned char) Count; + break; + } + phy_delay(phy_delay2); + } + + *OUI = (((unsigned long) PhyId1) << 6) | ((PhyId2 & 0xfc00) >> 10); + *Model = (unsigned char) ((PhyId2 & 0x03f0) >> 4); + *Revision = (unsigned char) (PhyId2 & 0x000f); + + return(PhyAdd); +} + + +static int +setup_phy(smcio_t ioaddr) +{ + int duplex = 0; /* 0 = Half, !0 = Full */ + int speed = 0; /* 0 = 10Mbps, !0 = 100Mbps */ + char *report = ""; + unsigned long OUI; + unsigned char Model, Revision; + + unsigned int i, PHYConfig, PHYConfig2, data; + unsigned char PHYAdd, ositech = 0; + + printk("SMCPHY: "); +#if 0 + ositech = 1; +#endif + + //Setting the AUI Select Bit for 91C110 PCMCIA Design. 11/23/99 PG + if (ositech) { + SMC_SELECT_BANK( 1 ); + data = inw(ioaddr + BANK_SELECT); + outw(data | 0x0100, ioaddr); + } + + if (MAC_IS_FEAST()) + SMC_SELECT_BANK ( 3 ); + + PHYAdd = DetectPHY(ioaddr, &OUI, &Model, &Revision); + + if (PHYAdd > 31) { + printk("UNRECOVERABLE ERROR: PHY is not present or not supported\n"); + return(-1); + } + + //Setup NV_CONTROL for the cardbus card. + if (OUI == PHY_OUI_TDK) + outw(0x7c03, ioaddr + NV_CONTROL); + + // Save Register 0. + + if (OUI == PHY_OUI_TDK) + PHYAccess(ioaddr, PHYAdd, PHY_CR, OPRead, 0); + PHYConfig = PHYAccess(ioaddr, PHYAdd,PHY_CR,OPRead,0); + + if (OUI == PHY_OUI_TDK) { + outw(0x0012, ioaddr + MIICFG); /* Set ENABLE_694 */ + /* if using EPIC, Hardware Reset the PHY from the MAC */ + outw(inw(ioaddr + CONTROL) | 0x4000, ioaddr + CONTROL); + phy_delay(phy_delay2); + outw(inw(ioaddr + CONTROL) & (~0x4000), ioaddr + CONTROL); + phy_delay(phy_delay2); + } + + /* Reset PHY */ + PHYAccess(ioaddr, PHYAdd, PHY_CR, OPWrite, PHY_CR_Reset); + if (OUI == PHY_OUI_TDK) + PHYAccess(ioaddr, PHYAdd, PHY_CR, OPWrite, PHY_CR_Reset); + + for (i = 0; i < 500; i++) { + if (OUI == PHY_OUI_TDK) + PHYAccess(ioaddr, PHYAdd, PHY_CR, OPRead, 0); + + if (PHYAccess(ioaddr, PHYAdd, PHY_CR, OPRead, 0) & PHY_CR_Reset) + phy_delay(phy_delay2); + else + break; + } + + if (i == 500) { + printk("UNRECOVERABLE ERROR: Could not reset PHY\n"); + return(-1); + } + + /* Write selected configuration to the PHY and verify it by reading back */ + /* Set Advertising Register for all 10/100 and Half/Full combinations */ + + if (OUI == PHY_OUI_TDK) + PHYConfig = PHYAccess(ioaddr, PHYAdd, 4, OPRead, 0); + PHYConfig = PHYAccess(ioaddr, PHYAdd, 4, OPRead, 0); + PHYConfig |= 0x01e0; + PHYAccess(ioaddr, PHYAdd, 4, OPWrite, PHYConfig); + if (OUI == PHY_OUI_TDK) + PHYAccess(ioaddr, PHYAdd, 4, OPWrite, PHYConfig); + + /* Start 1 */ + + /* National PHY requires clear before set 1 enable. */ + PHYAccess(ioaddr, PHYAdd, 0, OPWrite, 0x0000); + PHYAccess(ioaddr, PHYAdd, 0, OPWrite, 0x1200); + if (OUI == PHY_OUI_TDK) + PHYAccess(ioaddr, PHYAdd, 0, OPWrite, 0x1200); + + /* Wait for completion */ + for (i = 0; i < NWAY_TIMEOUT * 10; i++) { + printk("%c\b", "|/-\\"[i&3]); + + phy_delay(phy_delay3); + + PHYConfig = PHYAccess(ioaddr, PHYAdd, 1, OPRead, 0); + PHYConfig2 = PHYAccess(ioaddr, PHYAdd, 1, OPRead, 0); + + if (PHYConfig != PHYConfig2) /* Value is not stable */ + continue; + if (PHYConfig & 0x0010) /* Remote Fault */ + continue; + if ((PHYConfig == 0x0000) || (PHYConfig == 0xffff)) /* invalid value */ + continue; + if (PHYConfig & 0x0020) + break; + } + + /* Now read the results of the NWAY. */ + + if (OUI == PHY_OUI_TDK) + PHYConfig = PHYAccess(ioaddr, PHYAdd, 5, OPRead, 0); + PHYConfig = PHYAccess(ioaddr, PHYAdd, 5, OPRead, 0); + + if (PHYConfig != 0) { + /* Got real NWAY information here */ + report = "ANLPA"; + speed = (PHYConfig & 0x0180); + duplex = (PHYConfig & 0x0140); + } else { + /* + * ANLPA was 0 so NWAY did not complete or is not reported fine. + * Get the info from propietary regs or from the control register. + */ + report = "Prop."; /* Proprietary Status */ + + switch (OUI) { + case PHY_OUI_NATIONAL: + PHYConfig = PHYAccess(ioaddr, PHYAdd, PHY_NATIONAL_PAR, OPRead, 0); + duplex = (PHYConfig & PHY_NATIONAL_PAR_DUPLEX); + speed = ! (PHYConfig & PHY_NATIONAL_PAR_SPEED_10); + break; + + case PHY_OUI_TDK: + PHYConfig = PHYAccess(ioaddr, PHYAdd, PHY_TDK_DIAG, OPRead, 0); + PHYConfig = PHYAccess(ioaddr, PHYAdd, PHY_TDK_DIAG, OPRead, 0); + speed = ((Revision < 7) && ((PHYConfig & 0x300) == 0x300)) || + ((Revision >= 7) && (PHYConfig & PHY_TDK_DIAG_RATE)); + duplex = ((Revision >= 7) && (PHYConfig & PHY_TDK_DIAG_DUPLEX)); + break; + + case PHY_OUI_QSI: + PHYConfig = PHYAccess(ioaddr, PHYAdd, PHY_QSI_BASETX, OPRead, 0); + PHYConfig &= PHY_QSI_BASETX_OPMODE_MASK; + duplex = (PHYConfig & PHY_QSI_BASETX_OPMODE_10FD) || + (PHYConfig & PHY_QSI_BASETX_OPMODE_100FD); + speed = (PHYConfig & PHY_QSI_BASETX_OPMODE_100HD) || + (PHYConfig & PHY_QSI_BASETX_OPMODE_100FD); + break; + + case PHY_OUI_SEEQSMSC: + PHYConfig=PHYAccess(ioaddr,PHYAdd,PHY_SEEQ_STATUS_OUTPUT,OPRead,0); + duplex = (PHYConfig & PHY_SEEQ_DPLX_DET); + speed = (PHYConfig & PHY_SEEQ_SPD_DET); + break; + + default: + report = "Command"; + PHYConfig = PHYAccess(ioaddr, PHYAdd, 0, OPRead, 0); + speed = (PHYConfig & 0x2000); + duplex = (PHYConfig & 0x0100); + break; + } + } + + /* Do we need to adjust the Carrier sense on full duplex FEAST issue ? */ + + if (duplex && MAC_IS_FEAST() && (OUI == PHY_OUI_MITELSMSC)) + PHYAccess(ioaddr, PHYAdd, 0x18, OPWrite, + 0x0020 | PHYAccess(ioaddr, PHYAdd, 0x18, OPRead, 0)); + + /* Display what we learned */ + + printk(" %s-duplex %d Mbps ", duplex ? "Full" : "Half", speed ? 100 : 10); + + if (MAC_IS_FEAST()) + printk("FEAST "); + if (MAC_IS_EPIC()) + printk("EPIC "); + + switch (OUI) { + case PHY_OUI_QSI: printk("QSI"); break; + case PHY_OUI_TDK: printk("TDK"); break; + case PHY_OUI_MITELSMSC: printk("MITEL/SMSC180"); break; + case PHY_OUI_NATIONAL: printk("NATIONAL"); break; + case PHY_OUI_SEEQSMSC: printk("SEEQ/SMSC183"); break; + default: printk("%06lX(UNKNOWN)",OUI); break; + } + + printk(" Model=%02X Rev=%02X ", Model, Revision); +#if DEBUG + printk("Addr=%02X ", PHYAdd); + printk("Conf=%s ", report); +#endif + if (i == NWAY_TIMEOUT) + printk("TIMEOUT!\n"); + else + printk("Done.\n"); + return(0); +} + +/*----------------------------------------------------------- */ +#endif /* PHY_SETUP */ diff --git a/drivers/net/smc9194.h b/drivers/net/smc9194.h index cf69d0a5..cbb79f7d 100644 --- a/drivers/net/smc9194.h +++ b/drivers/net/smc9194.h @@ -96,6 +96,8 @@ typedef unsigned long int dword; /* BANK 1 */ #define CONFIG 0 #define CFG_AUI_SELECT 0x100 +#define CFG_NO_WAIT 0x1000 +#define CFG_MII_SELECT 0x8000 #define BASE 2 #define ADDR0 4 #define ADDR1 6 @@ -208,6 +210,44 @@ static const char * interfaces[ 2 ] = { "TP", "AUI" }; inw( ioaddr + RCR );\ inw( ioaddr + RCR ); } +#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68EZ328) + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) {\ + unsigned char mask;\ + SMC_SELECT_BANK(2);\ + mask = inb( ioaddr + INT_MASK );\ + mask |= (x);\ + outw( mask << 8, ioaddr + INTERRUPT ); \ +} + +/* this disables an interrupt from the interrupt mask register */ + +#define SMC_DISABLE_INT(x) {\ + unsigned char mask;\ + SMC_SELECT_BANK(2);\ + mask = inb( ioaddr + INT_MASK );\ + mask &= ~(x);\ + outw( mask << 8, ioaddr + INTERRUPT ); \ +} + +/* set the interrupt mask register */ +#define SMC_SET_INT(x) {\ + SMC_SELECT_BANK(2);\ + outw( ((unsigned short) (x)) << 8, ioaddr + INTERRUPT );\ +} + +/* acknowledge an interrupt */ +#define SMC_ACK_INT(x) {\ + unsigned short val;\ + /* assume BANK 2 selected */\ + val = inb( ioaddr + INT_MASK );\ + val = (val << 8) | (x);\ + outw( val, ioaddr + INTERRUPT );\ +} + +#else + /* this enables an interrupt in the interrupt mask register */ #define SMC_ENABLE_INT(x) {\ unsigned char mask;\ @@ -227,6 +267,17 @@ static const char * interfaces[ 2 ] = { "TP", "AUI" }; outb( mask, ioaddr + INT_MASK ); \ } +/* set the interrupt mask register */ +#define SMC_SET_INT(x) {\ + SMC_SELECT_BANK(2);\ + outb( (x), ioaddr + INT_MASK );\ +} + +/* acknowledge an interrupt */ +#define SMC_ACK_INT(x) outb( (x), ioaddr + INTERRUPT ) + +#endif + /*---------------------------------------------------------------------- . Define the interrupts that I want to receive from the card . diff --git a/drivers/net/stdphy.h b/drivers/net/stdphy.h new file mode 100644 index 00000000..6534005c --- /dev/null +++ b/drivers/net/stdphy.h @@ -0,0 +1,79 @@ +/*-------------------------------------------------------------------- + * stdphy.h + * + * 802.3 standard ethernet transceiver phy registers (0-8) + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Apr2004 DGT Microtronix Datacom + * + ---------------------------------------------------------------------*/ + +#ifndef _STDPHY_H_ + #define _STDPHY_H_ + +// PHY Control Register +#define PHY_CTL_REG 0x00 // Std Phy Reg0 + +#define PHY_CTL_RST_MASK 0x8000 // PHY Reset +#define PHY_CTL_LPBK_MASK 0x4000 // PHY Loopback +#define PHY_CTL_SPEED_MASK 0x2000 // 100Mbps, 0=10Mpbs +#define PHY_CTL_ANEG_EN_MASK 0x1000 // Enable Auto negotiation +#define PHY_CTL_PDN_MASK 0x0800 // PHY Power Down mode +#define PHY_CTL_MII_DIS_MASK 0x0400 // MII 4 bit interface disabled +#define PHY_CTL_ANEG_RST_MASK 0x0200 // Restart Auto negotiation +#define PHY_CTL_DPLX_MASK 0x0100 // Full Duplex (Else Half) +#define PHY_CTL_COLTST_MASK 0x0080 // MII Colision Test + +// PHY Status Register +#define PHY_STS_REG 0x01 // Std Phy Reg1 + +#define PHY_STS_CAP_T4_MASK 0x8000 // 100Base-T4 capable +#define PHY_STS_CAP_TXF_MASK 0x4000 // 100Base-X full duplex capable +#define PHY_STS_CAP_TXH_MASK 0x2000 // 100Base-X half duplex capable +#define PHY_STS_CAP_TF_MASK 0x1000 // 10Mbps full duplex capable +#define PHY_STS_CAP_TH_MASK 0x0800 // 10Mbps half duplex capable +#define PHY_STS_ANEGDONE_MASK 0x0020 // ANEG has completed +#define PHY_STS_REM_FLT_MASK 0x0010 // Remote Fault detected +#define PHY_STS_CAP_ANEG_MASK 0x0008 // Auto negotiate capable +#define PHY_STS_LNKSTS_MASK 0x0004 // Valid link +#define PHY_STS_JAB_MASK 0x0002 // 10Mbps jabber condition +#define PHY_STS_EXREG_MASK 0x0001 // Extended regs implemented + +// PHY Identifier Registers +#define PHY_ID1_REG 0x02 // Std Phy Reg2 +#define PHY_ID2_REG 0x03 // Std Phy Reg3 + +// PHY Auto-Negotiation Advertisement Register +#define PHY_ADV_REG 0x04 // Std Phy Reg4 + +#define PHY_ADV_T4 0x0200 // 100Base-T4 capable +#define PHY_ADV_TX_FDX 0x0100 // 100Base-TX FDPLX capable +#define PHY_ADV_TX_HDX 0x0080 // 100Base-TX HDPLX capable +#define PHY_ADV_10_FDX 0x0040 // 10Base-T FDPLX capable +#define PHY_ADV_10_HDX 0x0020 // 10Base-T HDPLX capable +#define PHY_ADV_CSMA 0x0001 // 802.3 CMSA capable + +// PHY Auto-negotiation Remote End Capability Register +#define PHY_REMCAP_REG 0x05 // Std Phy Reg5 + +#define PHY_REMCAP_T4 PHY_ADV_T4 +#define PHY_REMCAP_TX_FDX PHY_ADV_TX_FDX +#define PHY_REMCAP_TX_HDX PHY_ADV_TX_HDX +#define PHY_REMCAP_10_FDX PHY_ADV_10_FDX +#define PHY_REMCAP_10_HDX PHY_ADV_10_HDX +#define PHY_REMCAP_CSMA PHY_ADV_CSMA + +#endif /* _STDPHY_H_ */ diff --git a/drivers/net/tdk78phy.h b/drivers/net/tdk78phy.h new file mode 100644 index 00000000..649d8ed1 --- /dev/null +++ b/drivers/net/tdk78phy.h @@ -0,0 +1,44 @@ +/*-------------------------------------------------------------------- + * tdk78phy.h + * + * TDK 78Q2120 specific ethernet transceiver phy registers (09-18) + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Apr2004 DGT Microtronix Datacom + * + ---------------------------------------------------------------------*/ + +#ifndef _TDK78PHY_H_ + #define _TDK78PHY_H_ + + +// Interrupt Control/Status Register +#define TDK78_INTCTLSTS_REG 0x11 // Phy Reg17 +// +#define TDK78_INTIE_RXER_MASK 0x4000 // Rx error int enable +#define TDK78_INTIE_LSCHG_MASK 0x0400 // Link sts chg int enable +#define TDK78_INTIE_ANEGDONE_MASK 0x0100 // Auto neg done int enable +#define TDK78_INTSTS_RXER_MASK 0x0040 // Rx error (Read clears) +#define TDK78_INTSTS_LSCHG_MASK 0x0004 // Link sts chg (Read clears) +#define TDK78_INTSTS_ANEGDONE_MASK 0x0001 // Auto neg done (Read clears) + +// Diagnostic Register +#define TDK78_DIAG_REG 0x12 // Phy Reg18 +// +#define TDK78_DIAG_ANEGFAIL_MASK 0x1000 // Auto neg failed (Read clears) +#define TDK78_DIAG_FDUPLX_MASK 0x0800 // Full duplex +#define TDK78_DIAG_100TX_MASK 0x0400 // 100Base-TX + +#endif /* _TDK78PHY_H_ */ + diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a5449973..aff4f421 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1031,8 +1031,10 @@ EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_clear_mwi); EXPORT_SYMBOL_GPL(pci_intx); +#ifndef HAVE_ARCH_PCI_SET_DMA_MASK EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); +#endif EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index fc766a7a..f2dba707 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -260,6 +260,13 @@ config RTC_DRV_SH To compile this driver as a module, choose M here: the module will be called rtc-sh. +config RTC_DRV_DS1302 + tristate "DS1302 on SnapGear SuperH platforms" + depends on RTC_CLASS && SH_SECUREEDGE5410 + help + Say Y here to enable the DS1302 RTC on some SnapGear SuperH + based hardware platforms. + config RTC_DRV_VR41XX tristate "NEC VR41XX" depends on RTC_CLASS && CPU_VR41XX diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3ba5ff6e..611c16e4 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -35,4 +35,5 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o +obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c new file mode 100644 index 00000000..6054cfd1 --- /dev/null +++ b/drivers/rtc/rtc-ds1302.c @@ -0,0 +1,234 @@ +/****************************************************************************/ + +/* + * drivers/rtc/rtc-ds1302.c -- DS1302 RTC code + * + * Copyright (C) 2002 David McCullough + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2006 Greg Ungerer + * + * Support for the DS1302 on some Snapgear SH based boards. + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ +/* + * we need to implement a DS1302 driver here that can operate in + * conjunction with the builtin rtc driver which is already quite friendly + */ +/*****************************************************************************/ + +#define RTC_CMD_READ 0x81 /* Read command */ +#define RTC_CMD_WRITE 0x80 /* Write command */ + +#define RTC_ADDR_YEAR 0x06 /* Address of year register */ +#define RTC_ADDR_DAY 0x05 /* Address of day of week register */ +#define RTC_ADDR_MON 0x04 /* Address of month register */ +#define RTC_ADDR_DATE 0x03 /* Address of day of month register */ +#define RTC_ADDR_HOUR 0x02 /* Address of hour register */ +#define RTC_ADDR_MIN 0x01 /* Address of minute register */ +#define RTC_ADDR_SEC 0x00 /* Address of second register */ + +#define RTC_RESET 0x1000 +#define RTC_IODATA 0x0800 +#define RTC_SCLK 0x0400 + +#define set_dirp(x) +#define get_dirp(x) 0 +#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00) +#define get_dp(x) SECUREEDGE_READ_IOPORT() + +static void ds1302_sendbits(unsigned int val) +{ + int i; + + for (i = 8; (i); i--, val >>= 1) { + set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ? RTC_IODATA : 0)); + set_dp(get_dp() | RTC_SCLK); // clock high + set_dp(get_dp() & ~RTC_SCLK); // clock low + } +} + +static unsigned int ds1302_recvbits(void) +{ + unsigned int val; + int i; + + for (i = 0, val = 0; (i < 8); i++) { + val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i); + set_dp(get_dp() | RTC_SCLK); // clock high + set_dp(get_dp() & ~RTC_SCLK); // clock low + } + return(val); +} + +static unsigned int ds1302_readbyte(unsigned int addr) +{ + unsigned int val; + unsigned long flags; + + local_irq_save(flags); + set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + + set_dp(get_dp() | RTC_RESET); + ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ); + set_dirp(get_dirp() & ~RTC_IODATA); + val = ds1302_recvbits(); + set_dp(get_dp() & ~RTC_RESET); + local_irq_restore(flags); + + return(val); +} + +static void ds1302_writebyte(unsigned int addr, unsigned int val) +{ + unsigned long flags; + + local_irq_save(flags); + set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + set_dp(get_dp() | RTC_RESET); + ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE); + ds1302_sendbits(val); + set_dp(get_dp() & ~RTC_RESET); + local_irq_restore(flags); +} + +static void ds1302_reset(void) +{ + unsigned long flags; + /* Hardware dependant reset/init */ + local_irq_save(flags); + set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + local_irq_restore(flags); +} + +/****************************************************************************/ + +static inline int bcd2bin(int val) +{ + return BCD2BIN(val); +} + +static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(ds1302_readbyte(RTC_ADDR_SEC) & 0x7f); + tm->tm_min = bcd2bin(ds1302_readbyte(RTC_ADDR_MIN) & 0x7f); + tm->tm_hour = bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR) & 0x3f); + tm->tm_wday = bcd2bin(ds1302_readbyte(RTC_ADDR_DAY) & 0x07) - 1; + tm->tm_mday = bcd2bin(ds1302_readbyte(RTC_ADDR_DATE) & 0x3f); + tm->tm_mon = bcd2bin(ds1302_readbyte(RTC_ADDR_MON) & 0x1f) - 1; + tm->tm_year = bcd2bin(ds1302_readbyte(RTC_ADDR_YEAR)) + 100; + + return 0; +} + +static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + /* STOP RTC */ + ds1302_writebyte(RTC_ADDR_SEC, 0x80); + + ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min)); + ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour)); + ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday + 1)); + ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday)); + ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1)); + ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year - 100)); + + /* RESTARTS RTC */ + ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec)); + + return 0; +} + +/****************************************************************************/ + +static struct rtc_class_ops ds1302_rtc_ops = { + .read_time = ds1302_rtc_read_time, + .set_time = ds1302_rtc_set_time, +}; + +/****************************************************************************/ + +static int __devinit ds1302_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rdev; + unsigned char *test = "snapgear"; + int i; + + ds1302_reset(); + + for (i = 0; test[i]; i++) + ds1302_writebyte(32 + i, test[i]); + + for (i = 0; test[i]; i++) { + if (ds1302_readbyte(32 + i) != test[i]) + return -ENOENT; + } + + rdev = rtc_device_register("ds1302", &pdev->dev, &ds1302_rtc_ops, THIS_MODULE); + + printk("SnapGear RTC: using ds1302 rtc.\n"); + + platform_set_drvdata(pdev, rdev); + return 0; +} + +/****************************************************************************/ + +static int __devexit ds1302_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rdev = platform_get_drvdata(pdev); + + if (rdev) + rtc_device_unregister(rdev); + return 0; +} + +/****************************************************************************/ + +static struct platform_driver ds1302_rtc_platform_driver = { + .driver = { + .name = "ds1302", + .owner = THIS_MODULE, + }, + .probe = ds1302_rtc_probe, + .remove = __devexit_p(ds1302_rtc_remove), +}; + +/****************************************************************************/ + +static int __init ds1302_rtc_init(void) +{ + return platform_driver_register(&ds1302_rtc_platform_driver); +} + +static void __exit ds1302_rtc_exit(void) +{ + platform_driver_unregister(&ds1302_rtc_platform_driver); +} + +/****************************************************************************/ + +module_init(ds1302_rtc_init); +module_exit(ds1302_rtc_exit); + +/****************************************************************************/ + +MODULE_DESCRIPTION("DS1302 on SnapGear SH hardware platforms"); +MODULE_AUTHOR("David McCullough , Paul Mundt , Greg Ungerer "); +MODULE_LICENSE("GPL"); + +/****************************************************************************/ diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 143302a8..30251088 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -28,8 +28,12 @@ #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ #elif defined(CONFIG_CPU_SH4) #define rtc_reg_size sizeof(u32) +#if defined(CONFIG_CPU_SUBTYPE_SH7751R) +#define RTC_BIT_INVERTED 0 /* No bug on SH7751R? */ +#else #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ #endif +#endif #define RTC_REG(r) ((r) * rtc_reg_size) @@ -75,8 +79,7 @@ struct sh_rtc { static irqreturn_t sh_rtc_interrupt(int irq, void *id) { - struct platform_device *pdev = id; - struct sh_rtc *rtc = platform_get_drvdata(pdev); + struct sh_rtc *rtc = dev_get_drvdata(id); unsigned int tmp, events = 0; spin_lock(&rtc->lock); @@ -173,7 +176,6 @@ static int sh_rtc_open(struct device *dev) if (unlikely(ret)) { dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", ret, rtc->carry_irq); - free_irq(rtc->periodic_irq, dev); goto err_bad_carry; } @@ -246,8 +248,7 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_rtc *rtc = platform_get_drvdata(pdev); + struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int sec128, sec2, yr, yr100, cf_bit; do { @@ -305,8 +306,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_rtc *rtc = platform_get_drvdata(pdev); + struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int tmp; int year; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c59f3153..05ce0a0a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -659,7 +659,11 @@ void __scsi_done(struct scsi_cmnd *cmd) * The uptodate/nbytes values don't matter, as we allow partial * completes and thus will check this in the softirq callback */ +#if 0 // mask by Victor Yu. 07-24-2007 rq->completion_data = cmd; +#else + rq->u.completion_data = cmd; +#endif blk_complete_request(rq); } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3ac4890c..b7fd347e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1357,7 +1357,11 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) static void scsi_softirq_done(struct request *rq) { +#if 0 // mask by Victor Yu. 07-24-2007 struct scsi_cmnd *cmd = rq->completion_data; +#else + struct scsi_cmnd *cmd = rq->u.completion_data; +#endif unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command; int disposition; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 84ff203f..ddd4ffe9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -541,7 +541,11 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) **/ static int sd_open(struct inode *inode, struct file *filp) { +#if 0 // mask by Victor Yu. 07-24-2007 struct gendisk *disk = inode->i_bdev->bd_disk; +#else + struct gendisk *disk = inode->u.i_bdev->bd_disk; +#endif struct scsi_disk *sdkp; struct scsi_device *sdev; int retval; @@ -563,7 +567,11 @@ static int sd_open(struct inode *inode, struct file *filp) goto error_out; if (sdev->removable || sdkp->write_prot) +#if 0 // mask by Victor Yu. 07-24-2007 check_disk_change(inode->i_bdev); +#else + check_disk_change(inode->u.i_bdev); +#endif /* * If the drive is empty, just let the open fail. @@ -616,7 +624,11 @@ error_out: **/ static int sd_release(struct inode *inode, struct file *filp) { +#if 0 // mask by Victor Yu. 07-24-2007 struct gendisk *disk = inode->i_bdev->bd_disk; +#else + struct gendisk *disk = inode->u.i_bdev->bd_disk; +#endif struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdev = sdkp->device; @@ -676,7 +688,11 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) static int sd_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { +#if 0 // mask by Victor Yu. 07-24-2007 struct block_device *bdev = inode->i_bdev; +#else + struct block_device *bdev = inode->u.i_bdev; +#endif struct gendisk *disk = bdev->bd_disk; struct scsi_device *sdp = scsi_disk(disk)->device; void __user *p = (void __user *)arg; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e34bd03c..9f8e842c 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -40,6 +40,15 @@ #include #include #include +#include +#ifdef CONFIG_LEDMAN +#include +#endif + +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-08-2007 +#include +#include +#endif #include #include @@ -92,6 +101,20 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; */ #define CONFIG_HUB6 1 +#if defined(CONFIG_ARCH_SE4000) || defined(CONFIG_MACH_MONTEJADE) || \ + defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG565) || \ + defined(CONFIG_MACH_SG580) || defined(CONFIG_MACH_SG720) || \ + defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_SG8100) || \ + defined(CONFIG_MACH_SG590) +/* + * The XSCALE/IXP425 does not wire out the DCD and DTR lines. + * We implement them using GPIO lines on the SnapGear boards. + */ +#define CONFIG_IXP4XX_DTR0 0 +#define CONFIG_IXP4XX_DCD0 1 +#define CONFIG_IXP4XX_DCD0IRQ IRQ_IXP4XX_GPIO1 +#endif + #include /* @@ -927,7 +950,11 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) #endif scratch3 = serial_inp(up, UART_IER); serial_outp(up, UART_IER, scratch); +#ifdef CONFIG_ARCH_LPC22xx + if (scratch2 != 0 || scratch3&0x07 != 0x07) { +#else if (scratch2 != 0 || scratch3 != 0x0F) { +#endif /* * We failed; there's nothing here */ @@ -1182,6 +1209,11 @@ receive_chars(struct uart_8250_port *up, int *status) int max_count = 256; char flag; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (up->port.line == 0) ? LEDMAN_COM1_RX : LEDMAN_COM2_RX); +#endif + do { ch = serial_inp(up, UART_RX); flag = TTY_NORMAL; @@ -1252,6 +1284,11 @@ static void transmit_chars(struct uart_8250_port *up) struct circ_buf *xmit = &up->port.info->xmit; int count; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + (up->port.line == 0) ? LEDMAN_COM1_TX : LEDMAN_COM2_TX); +#endif + if (up->port.x_char) { serial_outp(up, UART_TX, up->port.x_char); up->port.icount.tx++; @@ -1426,8 +1463,18 @@ static int serial_link_irq_chain(struct uart_8250_port *up) i->head = &up->list; spin_unlock_irq(&i->lock); +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-08-2007 + cpe_int_set_irq(up->port.irq, LEVEL, H_ACTIVE); +#endif ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, "serial", i); +#ifdef CONFIG_IXP4XX_DCD0 + { + static irqreturn_t serial8250_interrupt_dcd(int irq, void *dev_id); + request_irq(7, serial8250_interrupt_dcd, SA_SHIRQ, + "serial(DCD)", up); + } +#endif if (ret < 0) serial_do_unlink(i, up); } @@ -1489,6 +1536,15 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) status = check_modem_status(up); +#ifdef CONFIG_IXP4XX_DCD0 + if (port->line == 0) { + int val; + gpio_line_get(CONFIG_IXP4XX_DCD0, &val); + status &= ~(UART_MSR_RI | UART_MSR_DCD); + status |= (val ? 0 : UART_MSR_DCD); + } +#endif + ret = 0; if (status & UART_MSR_DCD) ret |= TIOCM_CAR; @@ -1520,7 +1576,45 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; serial_out(up, UART_MCR, mcr); + +#ifdef CONFIG_IXP4XX_DTR0 + if (port->line == 0) { + if (mcr & UART_MCR_DTR) + gpio_line_set(CONFIG_IXP4XX_DTR0, 0); + else + gpio_line_set(CONFIG_IXP4XX_DTR0, 1); + } +#endif +} + +#ifdef CONFIG_IXP4XX_DTR0 +static void __init serial8250_initgpio(void) +{ + gpio_line_config(CONFIG_IXP4XX_DTR0, IXP4XX_GPIO_OUT); + gpio_line_config(CONFIG_IXP4XX_DCD0, IXP4XX_GPIO_IN); + set_irq_type(CONFIG_IXP4XX_DCD0IRQ, IRQT_BOTHEDGE); } +#else +#define serial8250_initgpio() do { } while (0) +#endif + +#ifdef CONFIG_IXP4XX_DCD0 +static irqreturn_t serial8250_interrupt_dcd(int irq, void *dev_id) +{ + struct uart_8250_port *up = dev_id; + unsigned int status; + + DEBUG_INTR("serial8250_interrupt_dcd(%d)...", irq); + + status = serial8250_get_mctrl((struct uart_port *) up); + uart_handle_dcd_change(&up->port, (status & TIOCM_CD) ? UART_MSR_DCD : 0); + wake_up_interruptible(&up->port.info->delta_msr_wait); + + DEBUG_INTR("end.\n"); + + return IRQ_HANDLED; +} +#endif /* CONFIG_IXP4XX_DCD0 */ static void serial8250_break_ctl(struct uart_port *port, int break_state) { @@ -1635,13 +1729,13 @@ static int serial8250_startup(struct uart_port *port) spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { if (!is_real_interrupt(up->port.irq)) - up->port.mctrl |= TIOCM_OUT1; + up->mcr_force |= UART_MCR_OUT1; } else /* * Most PC uarts need OUT2 raised to enable interrupts. */ if (is_real_interrupt(up->port.irq)) - up->port.mctrl |= TIOCM_OUT2; + up->mcr_force |= UART_MCR_OUT2; serial8250_set_mctrl(&up->port, up->port.mctrl); @@ -1710,9 +1804,9 @@ static void serial8250_shutdown(struct uart_port *port) if (up->port.flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ inb((up->port.iobase & 0xfe0) | 0x1f); - up->port.mctrl |= TIOCM_OUT1; + up->mcr_force |= UART_MCR_OUT2; } else - up->port.mctrl &= ~TIOCM_OUT2; + up->mcr_force &= ~UART_MCR_OUT2; serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); @@ -2648,6 +2742,8 @@ static int __init serial8250_init(void) "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); + serial8250_initgpio(); + for (i = 0; i < NR_IRQS; i++) spin_lock_init(&irq_lists[i].lock); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0b71e7d1..fe10c7f2 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -511,6 +511,30 @@ config SERIAL_IMX_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_KS8695 + bool "KS8695 built-in serial port" + depends on ARM && ARCH_KS8695 + select SERIAL_CORE + help + If you want to use the internal serial port of the KS8695 SoC + then say Y here. + +config SERIAL_KS8695_CONSOLE + bool "Console on KS8695 serial port" + depends on SERIAL_KS8695 + select SERIAL_CORE_CONSOLE + help + If you want the KS8695 internal serial port to be the default + system console, then Y here. + +config SERIAL_KS8695_COM + bool "Configure KS8695 serial port as ttyS0" + depends on SERIAL_KS8695 + help + If for compatability you need the standard serial port on the + KS8695 SoC to be ttyS0 instead of the usual ttyAM0 then say 'Y' + here. + config SERIAL_SUNCORE bool depends on SPARC @@ -681,6 +705,30 @@ config SERIAL_COLDFIRE This driver supports the built-in serial ports of the Motorola ColdFire family of CPUs. +config SERIAL_MCF + bool "Coldfire serial support (new style driver)" + depends on COLDFIRE + select SERIAL_CORE + help + This new serial driver supports the Freescale Coldfire serial ports + using the new serial driver subsystem. + +config SERIAL_MCF_BAUDRATE + int "Default baudrate for Coldfire serial ports" + depends on SERIAL_MCF + default 19200 + help + This setting lets you define what the default baudrate is for the + ColdFire serial ports. The usual default varies from board to board, + and this setting is a way of catering for that. + +config SERIAL_MCF_CONSOLE + bool "Coldfire serial console support" + depends on SERIAL_MCF + select SERIAL_CORE_CONSOLE + help + Enable a ColdFire internal serial port to be the system console. + config SERIAL_68360_SMC bool "68360 SMC uart support" depends on M68360 @@ -698,6 +746,38 @@ config SERIAL_68360 depends on SERIAL_68360_SMC || SERIAL_68360_SCC default y +config NIOS_SERIAL + bool "Nios serial support" + depends on NIOS || NIOS2 + help + This driver supports the Nios softcore UART port. + +config NIOS_SERIAL_CONSOLE + bool "Support for console on Nios UART" + depends on NIOS_SERIAL=y + help + If you would like to be able to use the Nios UART as the console, + you can do so by answering Y to this option. + default y + +config SERIAL_AJUART + tristate "Altera JTAG UART support" + depends on NIOS2 + select SERIAL_CORE + help + This driver supports the JTAG UART core (Avalon interface) + coming with Nios II softcore. + Say Y or M if you want to be able to use these serial ports. + +config SERIAL_AJUART_CONSOLE + bool "Support for console on Altera JTAG UART" + depends on SERIAL_AJUART=y + select SERIAL_CORE_CONSOLE + help + If you would like to be able to use the JTAG UART as the console, + you can do so by answering Y to this option. + default n + config SERIAL_PMACZILOG tristate "PowerMac z85c30 ESCC support" depends on PPC_OF && PPC_PMAC @@ -938,6 +1018,171 @@ config SERIAL_SGI_IOC4 and wish to use the serial ports on this card, say Y. Otherwise, say N. +config SERIAL_UC_ATMEL + bool "uClinux ATMEL uart support" + depends on ARCH_ATMEL + help + This driver supports the uart ports of the ATMEL AT91 series. + +config SERIAL_UC_ATMEL_CONSOLE + bool "Console on ATMEL uart" + depends on SERIAL_UC_ATMEL + help + If you would like to be able to use the ATMEL uart port + as the console, say Y to this option. + +config SERIAL_DM270 + tristate "DM270 on-chip UART support" + depends on MACH_DM270 + select SERIAL_CORE + help + Support for the on-chip UARTs on the TI TMS320DM270 CPU, + providing /dev/ttyS0 and 1. + +config SERIAL_DM270_BOOT_CTRL_UART1 + bool "Bootloader control activation of UART1" + depends on SERIAL_DM270 + default n + help + Say Y here if you want the bootloader to control whether UART1 + is enabled. + +config SERIAL_DM270_CONSOLE + bool "Support for console on DM270 on-chip UART" + depends on SERIAL_DM270 + select SERIAL_CORE_CONSOLE + help + Allow selection of the DM270 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=ttySx". + +config SERIAL_DCC + bool "JTAG ICE/ICD DCC serial port emulation support" + depends on ARM + select SERIAL_CORE + help + This selects serial port emulation driver for ICE/ICD JTAG debugger + (e.g. Trace32) for ARM architecture. You should make an terminal with + DCC(JTAG1) protocol. + + if unsure, say N. + +config SERIAL_DCC_CONSOLE + bool "Support for console on JTAG ICE/ICD DCC" + depends on SERIAL_DCC + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use ICE/ICD JTAG DCC serial port emulation + as the system console. you can use command line option "console=ttyJ0" + for manual console driver setup. + + if unsure, say N. + +config SERIAL_P2001_UART + tristate "P2001 uart driver" + depends on ARM && ARCH_P2001 + default y + select SERIAL_CORE + help + P2001 uart driver + +config SERIAL_P2001_UART_CONSOLE + bool "P2001 console on uart driver" + depends on SERIAL_P2001_UART=y + select SERIAL_CORE_CONSOLE + help + P2001 console on uart driver + +config SERIAL_S3C4510B + tristate "Samsung S3C4510B Serial port support" + depends on ARM && CPU_S3C4510B + select SERIAL_CORE + help + Support for the on-chip UARTs on the Samsung S3C4510B CPU, + providing /dev/ttyS0 and 1. + +config SERIAL_S3C4510B_CONSOLE + bool "Support for console on S3C4510B serial port" + depends on SERIAL_S3C4510B=y + select SERIAL_CORE_CONSOLE + help + Allow selection of the S3C4510B 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=ttySx". + +config SERIAL_S3C24A0 + tristate "Samsung S3C24A0 Serial port support" + depends on ARM && ARCH_S3C24A0 + select SERIAL_CORE + help + Support for the on-chip UARTs on the Samsung S3C24A0 CPU, + providing /dev/ttyS0 and 1. + + +config SERIAL_S3C24A0_CONSOLE + bool "Support for console on S3C24A0 serial port" + depends on SERIAL_S3C24A0=y + select SERIAL_CORE_CONSOLE + help + Allow selection of the S3C24A0 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=ttySx". + +config SERIAL_S3C4510B + tristate "Samsung S3C4510B Serial port support" + depends on ARM && CPU_S3C4510B + select SERIAL_CORE + help + Support for the on-chip UARTs on the Samsung S3C4510B CPU, + providing /dev/ttyS0 and 1. + +config SERIAL_S3C4510B_CONSOLE + bool "Support for console on S3C4510B serial port" + depends on SERIAL_S3C4510B=y + select SERIAL_CORE_CONSOLE + help + Allow selection of the S3C4510B 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=ttySx". + +config SERIAL_S3C24A0 + tristate "Samsung S3C24A0 Serial port support" + depends on ARM && ARCH_S3C24A0 + select SERIAL_CORE + help + Support for the on-chip UARTs on the Samsung S3C24A0 CPU, + providing /dev/ttyS0 and 1. + + +config SERIAL_S3C24A0_CONSOLE + bool "Support for console on S3C24A0 serial port" + depends on SERIAL_S3C24A0=y + select SERIAL_CORE_CONSOLE + help + Allow selection of the S3C24A0 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=ttySx". + config SERIAL_SGI_IOC3 tristate "SGI Altix IOC3 serial support" depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b4d8a7c1..44dbe185 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -36,14 +36,18 @@ 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_SERIAL_MCF) += mcf.o obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_NIOS_SERIAL) += NIOSserial.o +obj-$(CONFIG_SERIAL_AJUART) += altera_juart.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.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_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o @@ -53,6 +57,11 @@ obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o +obj-$(CONFIG_SERIAL_DCC) += dcc.o +obj-$(CONFIG_SERIAL_UC_ATMEL) += serial_atmel.o +obj-$(CONFIG_SERIAL_S3C4510B) += serial_s3c4510b.o +obj-$(CONFIG_SERIAL_P2001_UART) += p2001_uart.o +obj-$(CONFIG_SERIAL_DM270) += serial_dm270.o obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o diff --git a/drivers/serial/NIOSserial.c b/drivers/serial/NIOSserial.c new file mode 100644 index 00000000..0a0d99b6 --- /dev/null +++ b/drivers/serial/NIOSserial.c @@ -0,0 +1,1317 @@ +/*-------------------------------------------------------------------- + * + * drivers\serial\NIOSserial.c + * + * Serial port driver for builtin NIOS UART. + * + * Copyright (C) 1995 David S. Miller + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1998-2000 D. Jeff Dionne + * Copyright (C) 1999 Vladimir Gurevich + * Copyright (C) 2001 Vic Phillips + * Copyright (C) 2001 Wentao Xu + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "NIOSserial.h" + +#define DEBUG 1 + +//struct tty_struct NIOS_ttys; +//struct NIOS_serial *NIOS_consinfo = 0; + +#ifdef CONFIG_CONSOLE +extern wait_queue_head_t keypress_wait; +#endif + +struct tty_driver *serial_driver; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... DEBUG_INTR is bad to use when one of the zs + * lines is your console ;( + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define RS_ISR_PASS_LIMIT 256 + +#define _INLINE_ inline + +static void change_speed(struct NIOS_serial *info); + +/* + * Configuration table, UARTs to look for at startup. + */ +static struct NIOS_serial nios_soft[] = { +// { 0,0,1,0,0,0,0, (nasys_printf_uart), (nasys_printf_uart_irq) }, /* ttyS0 */ + { 0,0,1,0,0,0,0, (int) (na_uart0), (na_uart0_irq) }, /* ttyS0 */ +#ifdef na_uart1 +// { 0,0,0,0,0,0,0, (nasys_gdb_uart), (nasys_gdb_uart_irq) }, /* ttyS1 */ + { 0,0,0,0,0,0,0, (int) (na_uart1), (na_uart1_irq) }, /* ttyS1 */ +#endif +#ifdef na_uart2 + { 0,0,0,0,0,0,0, (int) (na_uart2), (na_uart2_irq) }, /* ttyS2 */ +#endif +#ifdef na_uart3 + { 0,0,0,0,0,0,0, (int) (na_uart3), (na_uart3_irq) }, /* ttyS3 */ +#endif +}; + +#define NR_PORTS (sizeof(nios_soft) / sizeof(struct NIOS_serial)) + + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */ +DECLARE_MUTEX(tmp_buf_sem); + +static inline int serial_paranoia_check(struct NIOS_serial *info, + char *name, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct %s in %s\n"; + static const char *badinfo = + "Warning: null nios_serial for %s in %s\n"; + + if (!info) { + printk(badinfo, name, routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, name, routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 0 }; + +/* Sets or clears DTR/RTS on the requested line */ +static inline void NIOS_rtsdtr(struct NIOS_serial *ss, int set) +{ + if (set) { + /* set the RTS/CTS line */ + } else { + /* clear it */ + } + return; +} + +/* Utility routines */ +static inline int get_baud(struct NIOS_serial *ss) +{ + return 0; /* not implemented yet */ +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + np_uart * uart= (np_uart *)(info->port); + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_stop")) + return; + + local_irq_save(flags); + uart->np_uartcontrol &= ~np_uartcontrol_itrdy_mask; + local_irq_restore(flags); +} + +static void rs_put_char(char ch, struct NIOS_serial *info) +{ + int flags, loops = 0; + np_uart * uart= (np_uart *)(info->port); + + local_irq_save(flags); + + while (!(uart->np_uartstatus & np_uartstatus_trdy_mask) && (loops < 100000)) { + loops++; + } + + uart->np_uarttxdata = ch; + local_irq_restore(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + if (serial_paranoia_check(info, tty->name, "rs_start")) + return; + + local_irq_save(flags); + if (info->xmit_cnt && info->xmit_buf && !(uart->np_uartcontrol & np_uartcontrol_itrdy_mask)) { +#ifdef USE_INTS + uart->np_uartcontrol &= np_uartcontrol_itrdy_mask; +#endif + } + local_irq_restore(flags); +} + +/* Drop into either the boot monitor or gdb upon receiving a break + * from keyboard/console input. + */ +#ifdef CONFIG_MAGIC_SYSRQ +static void batten_down_hatches(void) +{ + /* Drop into the debugger */ + // nios_gdb_breakpoint(); +} +#endif // CONFIG_MAGIC_SYSRQ + +static _INLINE_ void status_handle(struct NIOS_serial *info, unsigned short status) +{ + return; +} + +static _INLINE_ void receive_chars(struct NIOS_serial *info, unsigned short rx) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, flag; + np_uart * uart= (np_uart *)(info->port); + + /* + * This do { } while() loop will get ALL chars out of Rx FIFO + */ + do { + ch = uart->np_uartrxdata; + + if(info->is_cons) { +#ifdef CONFIG_MAGIC_SYSRQ + if(rx & np_uartstatus_brk_mask) { + batten_down_hatches(); + return; + } else if (ch == 0x10) { /* ^P */ + show_state(); + show_mem(); + return; +#ifdef DEBUG + } else if (ch == 0x02) { /* ^B */ + batten_down_hatches(); + return; +#endif + } +#endif /* CONFIG_MAGIC_SYSRQ */ + /* It is a 'keyboard interrupt' ;-) */ +#ifdef CONFIG_CONSOLE + wake_up(&keypress_wait); +#endif + } + + if(!tty) + goto clear_and_exit; + + flag = TTY_NORMAL; + + if(rx & np_uartstatus_pe_mask) { + flag = TTY_PARITY; + status_handle(info, rx); + } else if(rx & np_uartstatus_roe_mask) { + flag = TTY_OVERRUN; + status_handle(info, rx); + } else if(rx & np_uartstatus_fe_mask) { + flag = TTY_FRAME; + status_handle(info, rx); + } else if(rx & np_uartstatus_brk_mask) { + flag = TTY_BREAK; + status_handle(info, rx); + } + tty_insert_flip_char(tty, ch, flag); + + } while((rx = uart->np_uartstatus) & np_uartstatus_rrdy_mask); + + tty_schedule_flip(tty); + +clear_and_exit: + return; +} + +static _INLINE_ void transmit_chars(struct NIOS_serial *info) +{ + struct tty_struct *tty = info->tty; + np_uart * uart= (np_uart *)(info->port); + if (info->x_char) { + /* Send next char */ + uart->np_uarttxdata = info->x_char; + info->x_char = 0; + goto clear_and_return; + } + + if((info->xmit_cnt <= 0) || info->tty->stopped) { + /* That's peculiar... TX ints off */ + uart->np_uartcontrol &= ~np_uartcontrol_itrdy_mask; + goto clear_and_return; + } + + /* Send char */ + uart->np_uarttxdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + + if (info->xmit_cnt < WAKEUP_CHARS) + schedule_work(&info->tqueue); + + if(info->xmit_cnt <= 0) { + /* All done for now... TX ints off */ + uart->np_uartcontrol &= ~np_uartcontrol_itrdy_mask; + wake_up_interruptible(&tty->write_wait); + goto clear_and_return; + } + +clear_and_return: + /* Clear interrupt (should be auto)*/ + return; +} + +/* + * This is the serial driver's generic interrupt routine + */ +irqreturn_t rs_interrupt(int irq, void *dev_id) +{ + struct NIOS_serial * info = (struct NIOS_serial *) dev_id; + np_uart * uart= (np_uart *)(info->port); + unsigned short stat = uart->np_uartstatus; + uart->np_uartstatus = 0; /* clear any error status */ + + if (stat & np_uartstatus_rrdy_mask) receive_chars(info, stat); + if (stat & np_uartstatus_trdy_mask) transmit_chars(info); + return IRQ_HANDLED; +} + +static void do_softint(void *private) +{ + struct NIOS_serial *info = (struct NIOS_serial *) private; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct NIOS_serial *info = (struct NIOS_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + + + +static int startup(struct NIOS_serial * info) +{ + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + if (info->flags & S_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + local_irq_save(flags); + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + + change_speed(info); + + info->xmit_fifo_size = 1; + uart->np_uartcontrol = np_uartcontrol_itrdy_mask + | np_uartcontrol_irrdy_mask + | np_uartcontrol_ibrk_mask; + uart->np_uartrxdata; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + info->flags |= S_INITIALIZED; + local_irq_restore(flags); + return 0; +} + +/* + * 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 shutdown(struct NIOS_serial * info) +{ + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + uart->np_uartcontrol = 0; /* All off! */ + if (!(info->flags & S_INITIALIZED)) + return; + + local_irq_save(flags); /* Disable interrupts */ + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~S_INITIALIZED; + local_irq_restore(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct NIOS_serial *info) +{ +#if 1 /* NIOS usually has a fixed speed */ + +// unsigned long ustcnt; + unsigned cflag; + unsigned divisor; + int i; + np_uart * uart= (np_uart *)(info->port); + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + +// ustcnt = uart->np_uartcontrol; +// uart->np_uartcontrol = ustcnt & ~UCTRL_TE; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i = (i & ~CBAUDEX) + B38400; + } + + divisor = (unsigned)(((unsigned)nasys_clock_freq *1.0 / baud_table[i]) + 1) -1; + uart->np_uartdivisor = divisor; + if (uart->np_uartdivisor == divisor) + info->baud = baud_table[i]; + +// ustcnt &= ~(UCTRL_PE | UCTRL_PS); +// if ((cflag & CSIZE) == CS8) +// ustcnt |= USTCNT_8_7; +// if (cflag & CSTOPB) +// ustcnt |= USTCNT_STOP; +// if (cflag & PARENB) +// ustcnt |= UCTRL_PE; +// if (!(cflag & PARODD)) +// ustcnt |= UCTRL_PS; +// if (cflag & CRTSCTS) { +// ustcnt |= UCTRL_FL; +// } else { +// ustcnt &= ~UCTRL_FL; +// } +// ustcnt |= UCTRL_TE; +// uart->np_uartcontrol = ustcnt; + +#endif +} + +/* + * Fair output driver allows a process to speak. + */ +#if 0 +static void rs_fair_output(void) +{ + int left; /* Output no more than that */ + unsigned long flags; + struct NIOS_serial *info = &nios_soft; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + local_irq_save(flags); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + local_irq_restore(flags); + + rs_put_char(c, info); + + local_irq_save(flags); + left = min(info->xmit_cnt, left-1); + } + + /* Last character is being transmitted now (hopefully). */ + udelay(5); + + local_irq_restore(flags); + return; +} +#endif + +/* + * console_print_NIOS is registered for printk. + */ +void console_print_NIOS(const char *p) +{ + char c; + + while((c=*(p++)) != 0) { + if(c == '\n') + rs_put_char('\r', nios_soft); + rs_put_char(c, nios_soft); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + /* rs_fair_output(); */ + + return; +} + +static void rs_set_ldisc(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) + return; + + info->is_cons = (tty->termios->c_line == N_TTY); + + printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) + return; + + local_irq_save(flags); + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + goto flush_exit; + + /* Enable transmitter */ + + uart->np_uartcontrol |= np_uartcontrol_itrdy_mask; + + if (uart->np_uartstatus & np_uartstatus_trdy_mask) { + /* Send char */ + uart->np_uarttxdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + +flush_exit: + local_irq_restore(flags); +} + +extern void console_printn(const char * b, int count); + +static int rs_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + if (serial_paranoia_check(info, tty->name, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + local_save_flags(flags); + while (1) { + local_irq_disable(); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + local_irq_restore(flags); + buf += c; + count -= c; + total += c; + + } + + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + /* Enable transmitter */ + local_irq_disable(); + + uart->np_uartcontrol |= np_uartcontrol_itrdy_mask; + + if (uart->np_uartstatus & np_uartstatus_trdy_mask) { + uart->np_uarttxdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + + local_irq_restore(flags); + } + local_irq_restore(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->name, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) + return; + local_irq_disable(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_enable(); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line (do this atomic) */ +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line (do this atomic) */ +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct NIOS_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + return 0; +} + +static int set_serial_info(struct NIOS_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct NIOS_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + copy_from_user(&new_serial,new_info,sizeof(new_serial)); + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~S_USR_MASK) != + (info->flags & ~S_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~S_USR_MASK) | + (new_serial.flags & S_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~S_FLAGS) | + (new_serial.flags & S_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + retval = startup(info); + return retval; +} + +/* + * 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 int get_lsr_info(struct NIOS_serial * info, unsigned int *value) +{ + unsigned char status; + + status = 0; + put_user(status,value); + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break( struct NIOS_serial * info, int duration) +{ +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct NIOS_serial * info = (struct NIOS_serial *)tty->driver_data; + int retval; + + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSOFTCAR: + error = put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + if (error) + return error; + return 0; + case TIOCSSOFTCAR: + get_user(arg, (unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCGSERIAL: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + else + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct NIOS_serial)); + if (error) + return error; + copy_to_user((struct NIOS_serial *) arg, + info, sizeof(struct NIOS_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct NIOS_serial *info = (struct NIOS_serial *)tty->driver_data; + int oldbaud = info->baud; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + change_speed(info); + + if (info->baud == oldbaud) /* can not change */ + tty->termios->c_cflag = old_termios->c_cflag; + else /* only speed can be changed */ + tty->termios->c_cflag = (tty->termios->c_cflag & CBAUD) | CS8 | CREAD | HUPCL | CLOCAL; +#if 0 + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct NIOS_serial * info = (struct NIOS_serial *)tty->driver_data; + unsigned long flags; + np_uart * uart= (np_uart *)(info->port); + + if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + return; + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + local_irq_restore(flags); + return; + } + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + local_irq_restore(flags); + return; + } + info->flags |= S_CLOSING; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != S_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + uart->np_uartcontrol &= ~(np_uartcontrol_irrdy_mask); + + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } +#endif + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct NIOS_serial * info = (struct NIOS_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~S_NORMAL_ACTIVE; + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct NIOS_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & S_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= S_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + info->count--; + info->blocked_open++; + while (1) { + local_irq_disable(); + NIOS_rtsdtr(info, 1); + local_irq_enable(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & S_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & S_CLOSING) && do_clocal) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; + + if (retval) + return retval; + info->flags |= S_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its S structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct NIOS_serial *info; + int retval, line; + + line = tty->index; + + if (line >=serial_driver->num) /* too many */ + return -ENODEV; + + info = &nios_soft[line]; + + if (serial_paranoia_check(info, tty->name, "rs_open")) + return -ENODEV; + + info->count++; + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + return block_til_ready(tty, filp, info); +} + +/* Finally, routines used to initialize the serial driver. */ + +static void show_serial_version(void) +{ + printk("NIOS serial driver version 0.0\n"); +} + + + +static struct tty_operations rs_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .flush_buffer = rs_flush_buffer, + .ioctl = rs_ioctl, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, + .set_termios = rs_set_termios, + .stop = rs_stop, + .start = rs_start, + .hangup = rs_hangup, + .set_ldisc = rs_set_ldisc, +}; + +/* rs_init inits the driver */ +static int __init rs_nios_init(void) +{ + int flags; + struct NIOS_serial *info; + int i; + + serial_driver = alloc_tty_driver(NR_PORTS); + if (!serial_driver) + return -ENOMEM; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + /* SPARC: Not all of this is exactly right for us. */ + + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &rs_ops); + + if (tty_register_driver(serial_driver)) { + put_tty_driver(serial_driver); + printk(KERN_ERR "Couldn't register serial driver\n"); + return -ENOMEM; + } + + local_irq_save(flags); + + /* + * Configure all the attached serial ports. + */ + for (i = 0, info = nios_soft; (i < NR_PORTS); i++, info++) { + info->magic = SERIAL_MAGIC; + info->tty = 0; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->line = i; + + printk("%s%d (irq = %d) is a builtin NIOS UART\n", + serial_driver->name, info->line, info->irq); + +// rs_setsignals(info, 0, 0); + if (request_irq(info->irq, rs_interrupt, 0, "NIOS serial", info)) + panic("Unable to attach NIOS serial interrupt\n"); + } + + local_irq_restore(flags); + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +/* NIOS: Unused at this time, just here to make things link. */ +int register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ + return; +} + +module_init(rs_nios_init); + +#ifdef CONFIG_NIOS_SERIAL_CONSOLE +int nios_console_setup(struct console *cp, char *arg) +{ + return 0; +} + + +static struct tty_driver *nios_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + + +void nios_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + rs_put_char('\r', nios_soft); + rs_put_char( *str++, nios_soft); + } +} + + +static struct console nios_driver = { + .name = "ttyS", + .write = nios_console_write, + .device = nios_console_device, + .setup = nios_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + + +static int __init nios_console_init(void) +{ + register_console(&nios_driver); + return 0; +} + +console_initcall(nios_console_init); +#endif /* CONFIG_NIOS_SERIAL_CONSOLE */ diff --git a/drivers/serial/NIOSserial.h b/drivers/serial/NIOSserial.h new file mode 100644 index 00000000..08184084 --- /dev/null +++ b/drivers/serial/NIOSserial.h @@ -0,0 +1,123 @@ +/* NIOSserial.h: Definitions for the NIOS serial driver. + * + * Copyright (C) 1995 David S. Miller + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1998, 1999 D. Jeff Dionne + * Copyright (C) 1999 Vladimir Gurevich + * Copyright (C) 2001 Vic Phillips + * + */ + +#ifndef _NIOS_SERIAL_H +#define _NIOS_SERIAL_H + +#include + +/* + * 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__ + +/* + * 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 NIOS_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 */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + 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 + +/* + * 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 /* !(_NIOS_SERIAL_H) */ diff --git a/drivers/serial/altera_juart.c b/drivers/serial/altera_juart.c new file mode 100644 index 00000000..df46268d --- /dev/null +++ b/drivers/serial/altera_juart.c @@ -0,0 +1,505 @@ +/* + * linux/drivers/serial/altera_juart.c + * + * Driver for Altera JTAG UART core with Avalon interface + * + * Copyright 2004 Microtronix Datacom Ltd + * + * Based on linux/drivers/serial/amba.c, which is + * 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 + * + * Written by Wentao Xu + * Jun/20/2005 DGT Microtronix Datacom - support for + * arch/kernel/start.c - boot time error + * message(s). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_SERIAL_AJUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include //;dgt; + +#define UART_NR 1 + +#define SERIAL_JUART_MAJOR 232 +#define SERIAL_JUART_MINOR 16 +#define SERIAL_JUART_NR UART_NR + +#define JUART_ISR_PASS_LIMIT 16 + +/* + * Register maps + */ +#define JTAG_UARTDR 0 +#define JTAG_UARTCR 4 + +/* + * Control Register bit definition + */ +#define JTAG_UARTCR_RIE 1 +#define JTAG_UARTCR_TIE 2 +#define JTAG_UARTCR_RIS (1<<8) +#define JTAG_UARTCR_TIS (1<<9) +#define JTAG_UARTCR_AC (1<<10) + +/* + * Data Register + */ +#define JTAG_UARTDR_RVALID (1<<15) +#define JTAG_UARTDR_DATA 255 +/* + * Access macros for the JTAG UARTs + */ +#define UART_GET_DR(p) readl((p)->membase + JTAG_UARTDR) +#define UART_PUT_DR(p, c) writel((c), (p)->membase + JTAG_UARTDR) +#define UART_GET_CR(p) readl((p)->membase + JTAG_UARTCR) +#define UART_PUT_CR(p,c) writel((c), (p)->membase + JTAG_UARTCR) + +#define UART_PORT_SIZE 8 + + +/* + * We wrap our port structure around the generic uart_port. + */ +struct juart_port { + struct uart_port port; +}; + +static void jtaguart_stop_tx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CR(port); + cr &= ~JTAG_UARTCR_TIE; + UART_PUT_CR(port, cr); +} + +static void jtaguart_start_tx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CR(port); + cr |= JTAG_UARTCR_TIE; + UART_PUT_CR(port, cr); +} + +static void jtaguart_stop_rx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CR(port); + cr &= ~(JTAG_UARTCR_RIE); + UART_PUT_CR(port, cr); +} + +static void jtaguart_enable_ms(struct uart_port *port) +{ +} + +static void +#ifdef SUPPORT_SYSRQ +jtaguart_rx_chars(struct uart_port *port) +#else +jtaguart_rx_chars(struct uart_port *port) +#endif +{ + struct tty_struct *tty = port->info->tty; + unsigned int data, max_count = 256; + unsigned char flag; + + do { + data = UART_GET_DR(port); + if (!(data & JTAG_UARTDR_RVALID)) + return; + + port->icount.rx++; + + if(!tty) + goto clear_and_exit; + + flag = TTY_NORMAL; + + if (!uart_handle_sysrq_char(port, data & JTAG_UARTDR_DATA)) { + tty_insert_flip_char(tty, data & JTAG_UARTDR_DATA, flag); + } + + } while ((data >> 16) && (max_count--)); + + + tty_schedule_flip(tty); + +clear_and_exit: + return; +} + +static void jtaguart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) { + UART_PUT_DR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + jtaguart_stop_tx(port); + return; + } + + do { + UART_PUT_DR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (UART_GET_CR(port) >> 16); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + jtaguart_stop_tx(port); +} + +static irqreturn_t jtaguart_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned int status, pass_counter = JUART_ISR_PASS_LIMIT; + + status = UART_GET_CR(port); + do { + if (status & JTAG_UARTCR_RIS) +#ifdef SUPPORT_SYSRQ + jtaguart_rx_chars(port, regs); +#else + jtaguart_rx_chars(port); +#endif + if (status & JTAG_UARTCR_TIS) + jtaguart_tx_chars(port); + + if (pass_counter-- == 0) + break; + + status = UART_GET_CR(port); + } while ((status & JTAG_UARTCR_RIS) || + ((status & JTAG_UARTCR_TIS) && (status & JTAG_UARTCR_TIE))); + + return IRQ_HANDLED; +} + +static unsigned int jtaguart_tx_empty(struct uart_port *port) +{ + return ((UART_GET_CR(port)>>16) > 0 ) ? TIOCSER_TEMT : 0; +} + +static unsigned int jtaguart_get_mctrl(struct uart_port *port) +{ + return (TIOCM_CAR | TIOCM_DSR | TIOCM_CTS); +} + +static void jtaguart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void jtaguart_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int jtaguart_startup(struct uart_port *port) +{ + //struct juart_port *uap = (struct juart_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, jtaguart_int, 0, "jtag_uart", port); + if (retval) + return retval; + + /* + * Finally, enable reception interrupts + */ + UART_PUT_CR(port, JTAG_UARTCR_RIE); + + return 0; +} + +static void jtaguart_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* + * disable all interrupts, disable the port + */ + UART_PUT_CR(port, 0); +} + +static void +jtaguart_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + port->read_status_mask = 0; + port->ignore_status_mask = 0; +} + +static const char *jtaguart_type(struct uart_port *port) +{ + return port->type == PORT_JTAG_UART ? "jtag_uart" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void jtaguart_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 jtaguart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "jtag_uart") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void jtaguart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_JTAG_UART; + jtaguart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int jtaguart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_JTAG_UART) + 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 juart_pops = { + .tx_empty = jtaguart_tx_empty, + .set_mctrl = jtaguart_set_mctrl, + .get_mctrl = jtaguart_get_mctrl, + .stop_tx = jtaguart_stop_tx, + .start_tx = jtaguart_start_tx, + .stop_rx = jtaguart_stop_rx, + .enable_ms = jtaguart_enable_ms, + .break_ctl = jtaguart_break_ctl, + .startup = jtaguart_startup, + .shutdown = jtaguart_shutdown, + .set_termios = jtaguart_set_termios, + .type = jtaguart_type, + .release_port = jtaguart_release_port, + .request_port = jtaguart_request_port, + .config_port = jtaguart_config_port, + .verify_port = jtaguart_verify_port, +}; + +static struct juart_port juart_ports[UART_NR] = { + { + .port = { + .membase = (char*)na_jtag_uart, + .mapbase = na_jtag_uart, + .iotype = SERIAL_IO_MEM, + .irq = na_jtag_uart_irq, + .uartclk = 14745600, + .fifosize = 64, + .ops = &juart_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + } +}; + +#ifdef CONFIG_SERIAL_AJUART_CONSOLE + +//;dgt;static + void +jtaguart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &juart_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, 0); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_CR(port); + } while (!(status>>16)); + UART_PUT_DR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_CR(port); + } while (!(status>>16)); + UART_PUT_DR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the CR + * We don't have to wait until fifo is empty since + * the operation is irrevocable: all the chars can + * be deemed as "done" + */ + /*do { + status = UART_GET_CR(port); + } while ((status>>16)fifosize);*/ + UART_PUT_CR(port, old_cr); +} + +static void __init +jtaguart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + *parity = 'n'; + *bits = 8; + *baud = port->uartclk / 16; +} + +static int __init jtaguart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + 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 = &juart_ports[co->index].port; + + jtaguart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +extern struct uart_driver juart_reg; +//;dgt;static + struct console juart_console = { + .name = "ttyJ", + .write = jtaguart_console_write, + .device = uart_console_device, + .setup = jtaguart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &juart_reg, +}; + +static int __init jtaguart_console_init(void) +{ + register_console(&juart_console); + return 0; +} +console_initcall(jtaguart_console_init); + +#define JTAG_CONSOLE &juart_console +#else +#define JTAG_CONSOLE NULL +#endif + +static struct uart_driver juart_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyJ", + .dev_name = "ttyJ", + .major = SERIAL_JUART_MAJOR, + .minor = SERIAL_JUART_MINOR, + .nr = SERIAL_JUART_NR, + .cons = JTAG_CONSOLE, +}; + +static int __init jtaguart_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: JTAG UART driver $Revision: 1.3 $\n"); + + ret = uart_register_driver(&juart_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&juart_reg, &juart_ports[i].port); + } + return ret; +} + +static void __exit jtaguart_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&juart_reg, &juart_ports[i].port); + + uart_unregister_driver(&juart_reg); +} + +module_init(jtaguart_init); +module_exit(jtaguart_exit); + +MODULE_AUTHOR("Microtronix Datacom"); +MODULE_DESCRIPTION("Driver for Altera JTAG UART $Revision 1.0"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(SERIAL_JUART_MAJOR, SERIAL_JUART_MINOR); diff --git a/drivers/serial/dcc.c b/drivers/serial/dcc.c new file mode 100644 index 00000000..84cb4dd5 --- /dev/null +++ b/drivers/serial/dcc.c @@ -0,0 +1,550 @@ +/* + * linux/drivers/serial/dcc.c + * + * serial port emulation driver for the JTAG DCC Terminal. + * + * DCC(JTAG1) protocol version for JTAG ICE/ICD Debuggers: + * Copyright (C) 2003, 2004, 2005 Hyok S. Choi (hyok.choi@samsung.com) + * SAMSUNG ELECTRONICS Co.,Ltd. + * + * 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. + * + * Changelog: + * Oct-2003 Hyok S. Choi Created + * Feb-2004 Hyok S. Choi Updated for serial_core.c and 2.6 kernel + * Apr-2004 Hyok S. Choi xmit_string_CR added + * Mar-2005 Hyok S. Choi renamed from T32 to DCC + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if 0 + /* real irq interrupt used */ + #define DCC_IRQ_USED +#else + /* scheduled work used */ + #undef DCC_IRQ_USED +#endif + +#ifndef DCC_IRQ_USED +static struct work_struct dcc_poll_task; +static void dcc_poll(void *data); +#endif + +#define UART_NR 1 /* we have only one JTAG port */ + +#define SERIAL_DCC_NAME "ttyJ" +#define SERIAL_DCC_MAJOR 4 +#define SERIAL_DCC_MINOR 64 + +static int __inline__ __check_JTAG_RX_FLAG(void) +{ + int __ret=0; + __asm__ __volatile__( + " mrc p14, 0, %0, c0, c0 @ read comms control reg\n" + " and %0, %0, #1 @ jtag read buffer status" + : "=r" (__ret) + ); + + /* if __ret == 0 : no input yet + == 1 : a character pending */ + return __ret; +} + +static void __inline__ __get_JTAG_RX(volatile char *p) +{ + __asm__ __volatile__( + " mrc p14, 0, r3, c1, c0 @ read comms data reg to r5\n" + " strb r3, [%0] @ str a char" + : /* no output */ + : "r" (p) + : "r3", "memory"); +} + + +static int __inline__ __check_JTAG_TX_FLAG(void) +{ + int __ret=0; + __asm__ __volatile__( + " mrc p14, 0, %0, c0, c0 @ read comms control reg\n" + " and %0, %0, #2 @ the read buffer status" + : "=r" (__ret) + ); + + /* if __ret == 0 : tx is available + == 2 : tx busy */ + return __ret; +} + +void xmit_string(char *p, int len) +{ +#ifndef CONFIG_JTAG_DCC_OUTPUT_DISABLE + /* + r0 = string ; string address + r1 = 2 ; state check bit (write) + r4 = *string ; character + r7 = 0 ; count + */ + __asm__ __volatile__( + " mov r7, #0\n" + "1: mrc p14, 0, r3, c0, c0 @ read comms control reg\n" + " and r3, r3, #2 @ the write buffer status\n" + " cmp r3, #2 @ is it available?\n" + " beq 1b @ is not, wait till then\n" + " ldrb r4, [%0] @ load a char\n" + " mcr p14, 0, r4, c1, c0 @ write it\n" + " add %0, %0, #1 @ str address increase one\n" + " add r7, r7, #1 @ count increase\n" + " cmp r7, %1 @ compare with str length\n" + " bne 1b @ if it is not yet, loop" + : /* no output register */ + : "r" (p), "r" (len) + : "r7", "r3", "r4"); +#endif +} + +void xmit_string_CR(char *p, int len) +{ +#ifndef CONFIG_JTAG_DCC_OUTPUT_DISABLE + /* + r0 = string ; string address + r1 = 2 ; state check bit (write) + r4 = *string ; character + r7 = 0 ; count + */ + __asm__ __volatile__( + " mov r7, #0\n" + " ldrb r4, [%0] @ load a char\n" + "1: mrc p14, 0, r3, c0, c0 @ read comms control reg\n" + " and r3, r3, #2 @ the write buffer status\n" + " cmp r3, #2 @ is it available?\n" + " beq 1b @ is not, wait till then\n" + " mcr p14, 0, r4, c1, c0 @ write it\n" + " cmp r4, #0x0a @ is it LF?\n" + " bne 2f @ if it is not, continue\n" + " mov r4, #0x0d @ set the CR\n" + " b 1b @ loop for writing CR\n" + "2: ldrb r4, [%0, #1]! @ load a char\n" + " add r7, r7, #1 @ count increase\n" + " cmp r7, %1 @ compare with str length\n" + " bne 1b @ if it is not yet, loop" + : /* no output register */ + : "r" (p), "r" (len) + : "r7", "r3", "r4"); +#endif +} + + +static void +dcc_stop_tx(struct uart_port *port) +{ +} + +static inline void +dcc_transmit_buffer(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + int pendings = uart_circ_chars_pending(xmit); + + if(pendings + xmit->tail > UART_XMIT_SIZE) + { + xmit_string(&(xmit->buf[xmit->tail]), UART_XMIT_SIZE - xmit->tail); + xmit_string(&(xmit->buf[0]), xmit->head); + } else + xmit_string(&(xmit->buf[xmit->tail]), pendings); + + xmit->tail = (xmit->tail + pendings) & (UART_XMIT_SIZE-1); + port->icount.tx += pendings; + + if (uart_circ_empty(xmit)) + dcc_stop_tx(port); +} + +static inline void +dcc_transmit_x_char(struct uart_port *port) +{ + xmit_string(&port->x_char, 1); + port->icount.tx++; + port->x_char = 0; +} + +static void +dcc_start_tx(struct uart_port *port) +{ + dcc_transmit_buffer(port); +} + +static void +dcc_stop_rx(struct uart_port *port) +{ +} + +static void +dcc_enable_ms(struct uart_port *port) +{ +} + +static inline void +dcc_rx_chars(struct uart_port *port) +{ + unsigned char ch; + struct tty_struct *tty = port->info->tty; + + /* + * check input. + * checking JTAG flag is better to resolve the status test. + * incount is NOT used for JTAG1 protocol. + */ + + if (__check_JTAG_RX_FLAG()) + /* if __ret == 0 : no input yet + == 1 : a character pending */ + { + /* for JTAG 1 protocol, incount is always 1. */ + __get_JTAG_RX(&ch); + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.char_buf_ptr++ = ch; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + port->icount.rx++; + tty->flip.count++; + } + tty_flip_buffer_push(tty); + } +} + +static inline void +dcc_overrun_chars(struct uart_port *port) +{ + port->icount.overrun++; +} + +static inline void +dcc_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) { + dcc_transmit_x_char(port); + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + dcc_stop_tx(port); + return; + } + + dcc_transmit_buffer(port); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +#ifdef DCC_IRQ_USED /* real IRQ used */ +static irqreturn_t +dcc_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + int handled = 0; + + spin_lock(&port->lock); + + dcc_rx_chars(port); + dcc_tx_chars(port); + + handled = 1; + spin_unlock(&port->lock); + + return IRQ_RETVAL(handled); +} + +#else /* emulation by scheduled work */ +static void +dcc_poll(void *data) +{ + struct uart_port *port = data; + + spin_lock(&port->lock); + + dcc_rx_chars(port); + dcc_tx_chars(port); + + schedule_delayed_work(&dcc_poll_task, 1); + + spin_unlock(&port->lock); + +} +#endif /* end of DCC_IRQ_USED */ + +static unsigned int +dcc_tx_empty(struct uart_port *port) +{ + return TIOCSER_TEMT; +} + +static unsigned int +dcc_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void +dcc_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void +dcc_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int dcc_startup(struct uart_port *port) +{ +#ifdef DCC_IRQ_USED /* real IRQ used */ + int retval; + + /* Allocate the IRQ */ + retval = request_irq(port->irq, dcc_int, SA_INTERRUPT, + "serial_dcc", port); + if (retval) + return retval; +#else /* emulation */ + /* Initialize the work, and shcedule it. */ + INIT_WORK(&dcc_poll_task, dcc_poll, port); + schedule_delayed_work(&dcc_poll_task, 1); +#endif + + return 0; +} + +static void dcc_shutdown(struct uart_port *port) +{ +} + +static void +dcc_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ +#ifdef DCC_IRQ_USED + unsigned long flags; +#endif + unsigned int baud, quot; + + /* + * We don't support parity, stop bits, or anything other + * than 8 bits, so clear these termios flags. + */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CREAD); + termios->c_cflag |= CS8; + + /* + * We don't appear to support any error conditions either. + */ + termios->c_iflag &= ~(INPCK | IGNPAR | 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); + +#ifdef DCC_IRQ_USED + spin_lock_irqsave(&port->lock, flags); +#endif + + uart_update_timeout(port, termios->c_cflag, baud); + +#ifdef DCC_IRQ_USED + spin_unlock_irqrestore(&port->lock, flags); +#endif +} + +static const char *dcc_type(struct uart_port *port) +{ + return port->type == PORT_DCC_JTAG1 ? "DCC" : NULL; +} + +static void dcc_release_port(struct uart_port *port) +{ +} + +static int dcc_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void dcc_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_DCC_JTAG1; + dcc_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int dcc_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_DCC_JTAG1) + 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 dcc_pops = { + .tx_empty = dcc_tx_empty, + .set_mctrl = dcc_set_mctrl, + .get_mctrl = dcc_get_mctrl, + .stop_tx = dcc_stop_tx, + .start_tx = dcc_start_tx, + .stop_rx = dcc_stop_rx, + .enable_ms = dcc_enable_ms, + .break_ctl = dcc_break_ctl, + .startup = dcc_startup, + .shutdown = dcc_shutdown, + .set_termios = dcc_set_termios, + .type = dcc_type, + .release_port = dcc_release_port, + .request_port = dcc_request_port, + .config_port = dcc_config_port, + .verify_port = dcc_verify_port, +}; + +static struct uart_port dcc_ports[UART_NR] = { + { + .membase = (char*)0x12345678, /* we need these garbages */ + .mapbase = 0x12345678, /* for serial_core.c */ + .iotype = SERIAL_IO_MEM, +#ifdef DCC_IRQ_USED + .irq = INT_N_EXT0, +#else + .irq = 0, +#endif + .uartclk = 14745600, + .fifosize = 0, + .ops = &dcc_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, +}; + + +#ifdef CONFIG_SERIAL_DCC_CONSOLE + +static void +dcc_console_write(struct console *co, const char *s, unsigned int count) +{ + xmit_string_CR((char*)s, count); +} + +/* + * Read the current UART setup. + */ +static void __init +dcc_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +{ + *baud = 9600; + *parity = 'n'; + *bits = 8; +} + +static int __init +dcc_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= UART_NR) + co->index = 0; + port = &dcc_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + dcc_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +extern struct uart_driver dcc_reg; +static struct console dcc_console = { + .name = SERIAL_DCC_NAME, + .write = dcc_console_write, + .device = uart_console_device, + .setup = dcc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &dcc_reg, +}; + +static int __init dcc_console_init(void) +{ + register_console(&dcc_console); + return 0; +} +console_initcall(dcc_console_init); + +#define DCC_CONSOLE &dcc_console +#else +#define DCC_CONSOLE NULL +#endif + +static struct uart_driver dcc_reg = { + .owner = THIS_MODULE, + .driver_name = SERIAL_DCC_NAME, + .dev_name = SERIAL_DCC_NAME, + .major = SERIAL_DCC_MAJOR, + .minor = SERIAL_DCC_MINOR, + .nr = UART_NR, + .cons = DCC_CONSOLE, +}; + +static int __init +dcc_init(void) +{ + int ret; + + printk(KERN_INFO "DCC: JTAG1 Serial emulation driver driver $Revision: 1.3 $\n"); + + ret = uart_register_driver(&dcc_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&dcc_reg, &dcc_ports[i]); + } + return ret; +} + +__initcall(dcc_init); + +MODULE_DESCRIPTION("DCC(JTAG1) JTAG debugger console emulation driver"); +MODULE_AUTHOR("Hyok S. Choi "); +MODULE_SUPPORTED_DEVICE("ttyJ"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c new file mode 100644 index 00000000..2d169ae0 --- /dev/null +++ b/drivers/serial/mcf.c @@ -0,0 +1,828 @@ +/****************************************************************************/ + +/* + * mcf.c -- Freescale ColdFire UART driver + * + * (C) Copyright 2003-2006, Greg Ungerer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/****************************************************************************/ + +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(...) do { } while (0) +#endif + +/****************************************************************************/ + +/* + * On some ColdFire parts the IRQs for serial use are completely + * software programmable. On others they are pretty much fixed. + * On the programmed CPU's we arbitarily choose 73 (known not to + * interfere with anything else programed). + */ +#if defined(MCFINT_VECBASE) && defined(MCFINT_UART0) +#define IRQBASE (MCFINT_VECBASE + MCFINT_UART0) +#else +#define IRQBASE 73 +#endif + +/* + * Some boards implement the DTR/DCD lines using GPIO lines, most + * don't. Dummy out the access macros for those that don't. Those + * that do should define these macros somewhere in there board + * specific inlude files. + */ +#if !defined(mcf_getppdcd) +#define mcf_getppdcd(p) (1) +#endif +#if !defined(mcf_getppdtr) +#define mcf_getppdtr(p) (1) +#endif +#if !defined(mcf_setppdtr) +#define mcf_setppdtr(p,v) do { } while (0) +#endif + +/****************************************************************************/ + +/* + * Local per-uart structure. + */ +struct mcf_uart { + struct uart_port port; + unsigned int sigs; /* Local copy of line sigs */ + unsigned char imr; /* Local IMR mirror */ +}; + +/****************************************************************************/ + +static inline unsigned int mcf_getreg(struct uart_port *port, unsigned int reg) +{ + return readb(port->membase + reg); +} + +static inline void mcf_setreg(struct uart_port *port, unsigned int reg, unsigned int val) +{ + writeb(val, port->membase + reg); +} + +/****************************************************************************/ + +unsigned int mcf_tx_empty(struct uart_port *port) +{ + dprintk("mcf_tx_empty(port=%x)\n", (int)port); + + return (mcf_getreg(port, MCFUART_USR) & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; +} + +/****************************************************************************/ + +unsigned int mcf_get_mctrl(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + unsigned int sigs; + + dprintk(" mcf_get_mctrl(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + sigs = (mcf_getreg(port, MCFUART_UIPR) & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; + sigs |= (pp->sigs & TIOCM_RTS); + sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); + sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); + spin_unlock_irqrestore(&port->lock, flags); + return sigs; +} + +/****************************************************************************/ + +void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_set_mctrl(port=%x,sigs=%x)\n", (int)port, sigs); + + spin_lock_irqsave(&port->lock, flags); + pp->sigs = sigs; + mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); + if (sigs & TIOCM_RTS) + mcf_setreg(port, MCFUART_UOP1, MCFUART_UOP_RTS); + else + mcf_setreg(port, MCFUART_UOP0, MCFUART_UOP_RTS); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_start_tx(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_start_tx(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + pp->imr |= MCFUART_UIR_TXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_stop_tx(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_stop_tx(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + pp->imr &= ~MCFUART_UIR_TXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_start_rx(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_start_rx(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + pp->imr |= MCFUART_UIR_RXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_stop_rx(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_stop_rx(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + pp->imr &= ~MCFUART_UIR_RXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + + dprintk("mcf_break_ctl(port=%x,break_state=%x)\n", (int)port, break_state); + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDBREAKSTART); + else + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDBREAKSTOP); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_enable_ms(struct uart_port *port) +{ + dprintk("mcf_enable_ms(port=%x)\n", (int)port); +} + +/****************************************************************************/ + +int mcf_startup(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_startup(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + + /* Reset UART, get it into known state... */ + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETRX); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETTX); + + /* Enable the UART transmitter and receiver */ + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE); + + /* Enable RX interrupts now */ + pp->imr = MCFUART_UIR_RXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +/****************************************************************************/ + +void mcf_shutdown(struct uart_port *port) +{ + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned long flags; + + dprintk("mcf_shutdown(port=%x)\n", (int)port); + + spin_lock_irqsave(&port->lock, flags); + + /* Disable all interrupts now */ + pp->imr = 0; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + + /* Disable UART transmitter and receiver */ + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETRX); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETTX); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +void mcf_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ + unsigned long flags; + unsigned int baud, baudclk; + unsigned char mr1, mr2; + + dprintk("mcf_set_termios(port=%x,termios=%x,old=%x)\n", (int)port, (int)termios, (int)old); + + baud = uart_get_baud_rate(port, termios, old, 0, 230400); + baudclk = ((MCF_BUSCLK / baud) + 16) / 32; + + mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; + mr2 = 0; + + switch (termios->c_cflag & CSIZE) { + case CS5: mr1 |= MCFUART_MR1_CS5; break; + case CS6: mr1 |= MCFUART_MR1_CS6; break; + case CS7: mr1 |= MCFUART_MR1_CS7; break; + case CS8: + default: mr1 |= MCFUART_MR1_CS8; break; + } + + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYMARK; + else + mr1 |= MCFUART_MR1_PARITYSPACE; + } else { + if (termios->c_cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYODD; + else + mr1 |= MCFUART_MR1_PARITYEVEN; + } + } else { + mr1 |= MCFUART_MR1_PARITYNONE; + } + + if (termios->c_cflag & CSTOPB) + mr2 |= MCFUART_MR2_STOP2; + else + mr2 |= MCFUART_MR2_STOP1; + + if (termios->c_cflag & CRTSCTS) { + mr1 |= MCFUART_MR1_RXRTS; + mr2 |= MCFUART_MR2_TXCTS; + } + +#if 0 + printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__, + mr1, mr2, baudclk); +#endif + spin_lock_irqsave(&port->lock, flags); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETRX); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETTX); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETMRPTR); + mcf_setreg(port, MCFUART_UMR, mr1); + mcf_setreg(port, MCFUART_UMR, mr2); + mcf_setreg(port, MCFUART_UBG1, (baudclk & 0xff00) >> 8); + mcf_setreg(port, MCFUART_UBG2, (baudclk & 0xff)); + mcf_setreg(port, MCFUART_UCSR, MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER); + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +static void mcf_rx_chars(struct mcf_uart *pp) +{ + struct uart_port *port = (struct uart_port *) pp; + unsigned char status, ch, flag; + + while ((status = mcf_getreg(port, MCFUART_USR)) & MCFUART_USR_RXREADY) { + ch = mcf_getreg(port, MCFUART_URB); + flag = TTY_NORMAL; + port->icount.rx++; + + if (status & MCFUART_USR_RXERR) { + mcf_setreg(port, MCFUART_UCR, MCFUART_UCR_CMDRESETERR); + if (status & MCFUART_USR_RXBREAK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & MCFUART_USR_RXPARITY) { + port->icount.parity++; + } else if (status & MCFUART_USR_RXOVERRUN) { + port->icount.overrun++; + } else if (status & MCFUART_USR_RXFRAMING) { + port->icount.frame++; + } + + status &= port->read_status_mask; + + if (status & MCFUART_USR_RXBREAK) + flag = TTY_BREAK; + else if (status & MCFUART_USR_RXPARITY) + flag = TTY_PARITY; + else if (status & MCFUART_USR_RXFRAMING) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); + } + + tty_flip_buffer_push(port->info->tty); +} + +/****************************************************************************/ + +static void mcf_tx_chars(struct mcf_uart *pp) +{ + struct uart_port *port = (struct uart_port *) pp; + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) { + /* Send special char - probably flow control */ + mcf_setreg(port, MCFUART_UTB, port->x_char); + port->x_char = 0; + port->icount.tx++; + return; + } + + while (mcf_getreg(port, MCFUART_USR) & MCFUART_USR_TXREADY) { + if (xmit->head == xmit->tail) + break; + mcf_setreg(port, MCFUART_UTB, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (xmit->head == xmit->tail) { + pp->imr &= ~MCFUART_UIR_TXREADY; + mcf_setreg(port, MCFUART_UIMR, pp->imr); + } +} + +/****************************************************************************/ + +static irqreturn_t mcf_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + struct mcf_uart *pp = (struct mcf_uart *) port; + unsigned int isr; + + isr = mcf_getreg(port, MCFUART_UISR) & pp->imr; + if (isr & MCFUART_UIR_RXREADY) + mcf_rx_chars(pp); + if (isr & MCFUART_UIR_TXREADY) + mcf_tx_chars(pp); + return IRQ_HANDLED; +} + +/****************************************************************************/ + +void mcf_config_port(struct uart_port *port, int flags) +{ +#if defined(CONFIG_M5272) + unsigned long iop; + + switch (port->line) { + case 0: + writel(0xe0000000, (MCF_MBAR + MCFSIM_ICR2)); + break; + case 1: + writel(0x0e000000, (MCF_MBAR + MCFSIM_ICR2));; + break; + default: + printk("MCF: don't know how to handle UART %d interrupt?\n", + port->line); + return; + } + + /* Enable the output lines for the serial ports */ + iop = readl(MCF_MBAR + MCFSIM_PBCNT); + iop = (iop & ~0x000000ff) | 0x00000055; + writel(iop, MCF_MBAR + MCFSIM_PBCNT); + + iop = readl(MCF_MBAR + MCFSIM_PDCNT); + iop = (iop & ~0x000003fc) | 0x000002a8; + writel(iop, MCF_MBAR + MCFSIM_PBCNT); + +#elif defined(CONFIG_M523x) || defined(CONFIG_M528x) + unsigned long imr; + + /* level 6, line based priority */ + writeb(0x30 + port->line, MCF_MBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + port->line); + + imr = readl(MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + imr &= ~((1 << (port->irq - 64)) | 1); + writel(imr, MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + +#elif defined(CONFIG_M527x) + unsigned long imr; + unsigned short sem; + + /* level 6, line based priority */ + writeb(0x30 + port->line, MCF_MBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + port->line); + + imr = readl(MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + imr &= ~((1 << (port->irq - 64)) | 1); + writel(imr, MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + + sem = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (port->line == 0) + sem |= UART0_ENABLE_MASK; + else if (port->line == 1) + sem |= UART1_ENABLE_MASK; + else if (port->line == 2) + sem |= UART2_ENABLE_MASK; + writew(sem, MCF_IPSBAR + MCF_GPIO_PAR_UART); + +#elif defined(CONFIG_M520x) + unsigned long imr; + unsigned short par; + unsigned char par2; + + writeb(0x03, MCF_MBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + port->line); + + imr = readl(MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + imr &= ~((1 << (port->irq - MCFINT_VECBASE)) | 1); + writel(imr, MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); + + switch (port->line) { + case 0: + par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); + par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | + MCF_GPIO_PAR_UART_PAR_URXD0; + writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART); + break; + case 1: + par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); + par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | + MCF_GPIO_PAR_UART_PAR_URXD1; + writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART); + break; + case 2: + par2 = readb(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); + par2 &= ~0x0F; + par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | + MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + writeb(par2, MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); + break; + default: + printk("MCF: don't know how to handle UART %d interrupt?\n", + port->line); + break; + } + +#elif defined(CONFIG_M532x) + switch (port->line) { + case 0: + MCF_INTC0_ICR26 = 0x3; + MCF_INTC0_CIMR = 26; + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x000F; + break; + case 1: + MCF_INTC0_ICR27 = 0x3; + MCF_INTC0_CIMR = 27; + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x0FF0; + break; + case 2: + MCF_INTC0_ICR28 = 0x3; + MCF_INTC0_CIMR = 28; + /* GPIOs also must be initalized, depends on board */ + break; + } + +#else + volatile unsigned char *icrp; + + switch (port->line) { + case 0: + writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + break; + case 1: + writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); + break; + default: + printk("MCF: don't know how to handle UART %d interrupt?\n", + info->line); + return; + } + + mcfsetreg(port, MCFUART_UIVR, port->irq); +#endif + + port->type = PORT_MCF; + + /* Clear mask, so no surprise interrupts. */ + mcf_setreg(port, MCFUART_UIMR, 0); + + if (request_irq(port->irq, mcf_interrupt, SA_INTERRUPT, + "ColdFire UART", port)) { + printk("MCF: Unable to attach ColdFire UART %d interrupt " + "vector=%d\n", port->line, port->irq); + } + +} + +/****************************************************************************/ + +static const char *mcf_type(struct uart_port *port) +{ + dprintk("mcf_type()\n"); + return ((port->type == PORT_MCF) ? "ColdFire UART" : NULL); +} + +/****************************************************************************/ + +int mcf_request_port(struct uart_port *port) +{ + /* UARTs always present */ + dprintk("mcf_request_port()\n"); + return 0; +} + +/****************************************************************************/ + +void mcf_release_port(struct uart_port *port) +{ + /* Nothing to release... */ + dprintk("mcf_release_port()\n"); +} + +/****************************************************************************/ + +int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + dprintk("mcf_verify_port()\n"); + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF)) + return -EINVAL; + return 0; +} + +/****************************************************************************/ + +/* + * Define the basic serial functions we support. + */ +static struct uart_ops mcf_uart_ops= { + .tx_empty = mcf_tx_empty, + .get_mctrl = mcf_get_mctrl, + .set_mctrl = mcf_set_mctrl, + .start_tx = mcf_start_tx, + .stop_tx = mcf_stop_tx, + .stop_rx = mcf_stop_rx, + .enable_ms = mcf_enable_ms, + .break_ctl = mcf_break_ctl, + .startup = mcf_startup, + .shutdown = mcf_shutdown, + .set_termios = mcf_set_termios, + .type = mcf_type, + .request_port = mcf_request_port, + .release_port = mcf_release_port, + .config_port = mcf_config_port, + .verify_port = mcf_verify_port, +}; + +/* + * Define the port structures, 1 per port/uart. + */ +static struct mcf_uart mcf_ports[] = { + { + .port = { + .line = 0, + .type = PORT_MCF, + .membase = (void *) MCF_MBAR + MCFUART_BASE1, + .mapbase = MCF_MBAR + MCFUART_BASE1, + .iotype = SERIAL_IO_MEM, + .irq = IRQBASE, + .uartclk = MCF_BUSCLK, + .ops = &mcf_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + }, + }, +#if defined(MCFUART_BASE2) + { + .port = { + .line = 1, + .type = PORT_MCF, + .membase = (void *) MCF_MBAR + MCFUART_BASE2, + .mapbase = MCF_MBAR + MCFUART_BASE2, + .iotype = SERIAL_IO_MEM, + .irq = IRQBASE + 1, + .uartclk = MCF_BUSCLK, + .ops = &mcf_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + }, + }, +#endif +#if defined(MCFUART_BASE3) + { + .port = { + .line = 2, + .type = PORT_MCF, + .membase = (void *) MCF_MBAR + MCFUART_BASE3, + .mapbase = MCF_MBAR + MCFUART_BASE3, + .iotype = SERIAL_IO_MEM, + .irq = IRQBASE + 2, + .uartclk = MCF_BUSCLK, + .ops = &mcf_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + }, + } +#endif +}; + +#define MCF_MAXPORTS (sizeof(mcf_ports) / sizeof(struct mcf_uart)) + +/****************************************************************************/ +#if defined(CONFIG_SERIAL_MCF_CONSOLE) +/****************************************************************************/ + +static void mcf_console_putc(struct console *co, const char c) +{ + struct uart_port *port = &(mcf_ports + co->index)->port; + int i; + + for (i = 0; (i < 0x10000); i++) { + if (mcf_getreg(port, MCFUART_USR) & MCFUART_USR_TXREADY) + break; + } + mcf_setreg(port, MCFUART_UTB, c); + for (i = 0; (i < 0x10000); i++) { + if (mcf_getreg(port, MCFUART_USR) & MCFUART_USR_TXREADY) + break; + } +} + +/****************************************************************************/ + +static void mcf_console_write(struct console *co, const char *s, unsigned int count) +{ + for ( ; (count); count--, s++) { + mcf_console_putc(co, *s); + if (*s == '\n') + mcf_console_putc(co, '\r'); + } +} + +/****************************************************************************/ + +static int __init mcf_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = CONFIG_SERIAL_MCF_BAUDRATE; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if ((co->index >= 0) && (co->index <= MCF_MAXPORTS)) + co->index = 0; + port = &mcf_ports[co->index].port; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +/****************************************************************************/ + +static struct uart_driver mcf_driver; + +static struct console mcf_console = { + .name = "ttyS", + .write = mcf_console_write, + .device = uart_console_device, + .setup = mcf_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &mcf_driver, +}; + +static int __init mcf_console_init(void) +{ + register_console(&mcf_console); + return 0; +} + +console_initcall(mcf_console_init); + +#define MCF_CONSOLE &mcf_console + +/****************************************************************************/ +#else +/****************************************************************************/ + +#define MCF_CONSOLE NULL + +/****************************************************************************/ +#endif /* CONFIG_MCF_CONSOLE */ +/****************************************************************************/ + +/* + * Define the mcf UART driver structure. + */ +static struct uart_driver mcf_driver = { + .owner = THIS_MODULE, + .driver_name = "mcf", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = MCF_MAXPORTS, + .cons = MCF_CONSOLE, +}; + +/****************************************************************************/ + +static int __init mcf_init(void) +{ + int i, rc; + + printk("ColdFire internal UART serial driver\n"); + + if ((rc = uart_register_driver(&mcf_driver))) + return rc; + + for (i = 0; (i < MCF_MAXPORTS); i++) { + if ((rc = uart_add_one_port(&mcf_driver, &mcf_ports[i].port)) < 0) + printk("mcf: failed to add UART, %d\n", rc); + } + return 0; +} + +/****************************************************************************/ + +static void __exit mcf_exit(void) +{ + int i; + + for (i = 0; (i < MCF_MAXPORTS); i++) + uart_remove_one_port(&mcf_driver, &mcf_ports[i].port); + uart_unregister_driver(&mcf_driver); +} + +/****************************************************************************/ + +module_init(mcf_init); +module_exit(mcf_exit); + +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("Freescale ColdFire UART driver"); +MODULE_LICENSE("GPL"); + +/****************************************************************************/ diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index aee1b31f..9f0a4d9e 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -60,7 +60,8 @@ struct timer_list mcfrs_timer_struct; #if defined(CONFIG_HW_FEITH) #define CONSOLE_BAUD_RATE 38400 #define DEFAULT_CBAUD B38400 -#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || defined(CONFIG_M5329EVB) +#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ + defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) #define CONSOLE_BAUD_RATE 115200 #define DEFAULT_CBAUD B115200 #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ @@ -109,12 +110,30 @@ static struct mcf_serial mcfrs_table[] = { .irq = IRQBASE, .flags = ASYNC_BOOT_AUTOCONF, }, +#ifdef MCFUART_BASE2 { /* ttyS1 */ .magic = 0, .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), .irq = IRQBASE+1, .flags = ASYNC_BOOT_AUTOCONF, }, +#endif +#ifdef MCFUART_BASE3 + { /* ttyS2 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), + .irq = IRQBASE+2, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif +#ifdef MCFUART_BASE4 + { /* ttyS3 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), + .irq = IRQBASE+3, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif }; @@ -838,7 +857,7 @@ static void mcfrs_throttle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -857,7 +876,7 @@ static void mcfrs_unthrottle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1516,6 +1535,29 @@ static void mcfrs_irqinit(struct mcf_serial *info) imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +#if defined(CONFIG_M527x) + { + /* + * External Pin Mask Setting & Enable External Pin for Interface + * mrcbis@aliceposta.it + */ + unsigned short *serpin_enable_mask; + serpin_enable_mask = (MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (info->line == 0) + *serpin_enable_mask |= UART0_ENABLE_MASK; + else if (info->line == 1) + *serpin_enable_mask |= UART1_ENABLE_MASK; + else if (info->line == 2) + *serpin_enable_mask |= UART2_ENABLE_MASK; + } +#endif +#if defined(CONFIG_M528x) + /* make sure PUAPAR is set for UART0 and UART1 */ + if (info->line < 2) { + volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); + *portp |= (0x03 << (info->line * 2)); + } +#endif #elif defined(CONFIG_M520x) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; @@ -1713,7 +1755,7 @@ mcfrs_init(void) /* Initialize the tty_driver structure */ mcfrs_serial_driver->owner = THIS_MODULE; mcfrs_serial_driver->name = "ttyS"; - mcfrs_serial_driver->driver_name = "serial"; + mcfrs_serial_driver->driver_name = "mcfserial"; mcfrs_serial_driver->major = TTY_MAJOR; mcfrs_serial_driver->minor_start = 64; mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; @@ -1797,10 +1839,23 @@ void mcfrs_init_console(void) uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; +#ifdef CONFIG_M5272 +{ + /* + * For the MCF5272, also compute the baudrate fraction. + */ + int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); + fraction *= 16; + fraction /= (32 * mcfrs_console_baud); + uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ + clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; +} +#else clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ +#endif + uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; diff --git a/drivers/serial/p2001_uart.c b/drivers/serial/p2001_uart.c new file mode 100644 index 00000000..c410b0c8 --- /dev/null +++ b/drivers/serial/p2001_uart.c @@ -0,0 +1,720 @@ +/* + * linux/drivers/char/p2001_uart.c + * + * Driver for P2001 uart port + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 + */ + +/* + * Version 1.0: First working version + * Version 1.1: Removed all READ_REG/WRITE_REG + * Version 1.2: Break handling + * Version 1.3: Hardware handshake + * Device naming, major/minor nr for setserial + * ISR cleanups + * Version 1.4: cpu frequency scaling + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CPU_FREQ +#include +#include +#endif + +#include +#include +#include + +#if defined(CONFIG_SERIAL_P2001_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + + +/************************************************************************** + * Definitions + **************************************************************************/ +static const char *version = + "p2001_uart.c:v1.4 12/29/2004 Tobias Lorenz (tobias.lorenz@gmx.net)\n"; + +static const char p2001_uart_name[] = "P2001 uart"; + +#define TX_MIN_BUF 10 + +#define tx_enabled(port) ((port)->unused[0]) +#define rx_enabled(port) ((port)->unused[1]) + +extern struct uart_driver p2001_uart_driver; /* UART Driver */ +extern struct uart_port p2001_uart_port; /* UART Port */ +extern struct uart_ops p2001_uart_ops; /* UART Operations */ +extern struct console p2001_console; /* Console */ + +#define DEFAULT_BAUD 57600 +static unsigned int baud; /* Current baudrate */ + + + +/************************************************************************** + * UART Driver + **************************************************************************/ + +static struct uart_driver p2001_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "serial", /* name of tty/console device */ + .dev_name = "ttyS", /* name of tty/console device */ +#ifdef CONFIG_DEVFS_FS + .devfs_name = "tts/", /* name of tty/console device */ +#endif + .major = 4, /* major number for the driver */ + .minor = 64, /* starting minor number */ + .nr = 1, /* maximum number of serial ports this driver supports */ +#ifdef CONFIG_SERIAL_P2001_UART_CONSOLE + .cons = &p2001_console, +#endif +}; + + + +/************************************************************************** + * UART Port + **************************************************************************/ + +static struct uart_port p2001_uart_port = { + .membase = (void*)P2001_UART, /* read/write[bwl] */ + .mapbase = (unsigned int)P2001_UART, /* for ioremap */ + .iotype = UPIO_MEM, /* io access style */ + .irq = IRQ_UART, /* irq number */ + .uartclk = CONFIG_SYSCLK/8, /* base uart clock */ + .fifosize = 32, /* tx fifo size */ + .ops = &p2001_uart_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 0, /* port index */ +}; + + + +/************************************************************************** + * UART interrupt routine + **************************************************************************/ + +/* uart interrupt send routine */ +static void p2001_uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int count; + + if (port->x_char) { + while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF) + barrier(); + P2001_UART->w.TX[0] = port->x_char; + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + tx_enabled(port) = 0; + return; + } + + count = port->fifosize >> 1; + do { + while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF) + barrier(); + P2001_UART->w.TX[0] = 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)) + tx_enabled(port) = 0; + + P2001_UART->w.IRQ_Status |= (1<<0); +} + +/* uart interrupt receive routine */ +static void p2001_uart_rx_chars(struct uart_port *port, struct pt_regs *regs) +{ + struct tty_struct *tty = port->info->tty; + unsigned int status; + unsigned int rxddelta; + unsigned int rx; + unsigned int max_count = 256; + + status = P2001_UART->r.IRQ_Status; + rxddelta = (P2001_UART->r.STATUS >> 6) & 0x3f; + while (rxddelta && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.work.func((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + rx = P2001_UART->r.RX[0]; + + *tty->flip.char_buf_ptr = rx & 0xff; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (status & ((1<<7)|(1<<6)|(1<<9))) { + if (status & (1<<7)) { /* RxD_BRK */ + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_chars; + } else if (status & (1<<6)) /* RxD_FIFO_PAR_ERR */ + port->icount.parity++; + if (status & (1<<9)) /* RxD_LOST */ + port->icount.overrun++; + + status &= port->read_status_mask; + + if (status & (1<<7)) /* RxD_BRK */ + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (status & (1<<6)) /* RxD_FIFO_PAR_ERR */ + *tty->flip.flag_buf_ptr = TTY_PARITY; + + } + + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_chars; + + if (rx && port->ignore_status_mask == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((status & (1<<9)) && /* RxD_LOST */ + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + ignore_chars: + rxddelta = (P2001_UART->r.STATUS >> 6) & 0x3f; + } + tty_flip_buffer_push(tty); + + P2001_UART->w.IRQ_Status |= (1<<3) | (1<<6) | (1<<7) | (1<<9); +} + +/* uart interrupt routine */ +static irqreturn_t p2001_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + unsigned int status; + + spin_lock(&port->lock); + + status = P2001_UART->r.IRQ_Status; + // TXD_SEND | TXD_LAST_DATA + if (status & (1<<0)) // (1<<2) + p2001_uart_tx_chars(port); + // RXD_DATA | RxD_FIFO_PAR_ERR | RxD_BRK | RxD_LOST + if (status & ((1<<3) | (1<<6) | (1<<7) | (1<<9))) + p2001_uart_rx_chars(port, regs); + + //status &= ~((1<<0) | (1<<2) | (1<<3)); + //if (status & 0x3ff) + // printk(KERN_INFO "p2001_uart_interrupt: status=0x%8.8x\n", status); + + P2001_UART->w.IRQ_Status &= ~0x3ff; + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + + + +/************************************************************************** + * UART Operations + **************************************************************************/ + +/* returns if the port transmitter is empty or not. */ +static unsigned int p2001_uart_ops_tx_empty(struct uart_port *port) +{ + unsigned int txddelta = P2001_UART->r.STATUS & 0x3f; + return (txddelta > 0) ? 0 : TIOCSER_TEMT; +} + +/* sets a new value for the MCR UART register. */ +static void p2001_uart_ops_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* no modem control lines */ +} + +/* gets the current MCR UART register value. */ +static unsigned int p2001_uart_ops_get_mctrl(struct uart_port *port) +{ + /* no modem control lines */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* stops the port from sending data. */ +static void p2001_uart_ops_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + P2001_UART->w.IRQ_Status &= ~((1<<20) | (1<<22)); // TXD_SEND | TXD_LAST_DATA + tx_enabled(port) = 0; + } +} + +/* starts the port sending data. */ +static void p2001_uart_ops_start_tx(struct uart_port *port) +{ + if (!tx_enabled(port)) { + P2001_UART->w.IRQ_Status |= (1<<20) | (1<<22); // TXD_SEND | TXD_LAST_DATA + tx_enabled(port) = 1; + } + p2001_uart_tx_chars(port); +} + +/* tells the port to send the XOFF character to the host. */ +#if 0 +static void p2001_uart_ops_send_xchar(struct uart_port *port, char ch) +{ +#warning "p2001_uart_ops_send_xchar is not implemented." +} +#endif + +/* stops receiving data. */ +static void p2001_uart_ops_stop_rx(struct uart_port *port) +{ + if (rx_enabled(port)) { + P2001_UART->w.IRQ_Status &= ~(1<<23); // RXD_DATA + rx_enabled(port) = 0; + } +} + +/* enables the modem status interrupts. */ +static void p2001_uart_ops_enable_ms(struct uart_port *port) +{ + /* empty */ +} + +/* sends the BREAK value over the port. */ +static void p2001_uart_ops_break_ctl(struct uart_port *port, int ctl) +{ + /* no break signal */ +} + +/* called once each time the open call happens */ +static int p2001_uart_ops_startup(struct uart_port *port) +{ + int ret; + + tx_enabled(port) = 1; + rx_enabled(port) = 1; + + ret = request_irq(port->irq, p2001_uart_interrupt, 0, p2001_uart_name, port); + + P2001_UART->w.Clear = 0; + // TXD_SEND | TXD_LAST_DATA + P2001_UART->w.IRQ_Status |= (1<<20) | (1<<22); + // RXD_DATA | RxD_FIFO_PAR_ERR | RxD_BRK | RxD_LOST + P2001_UART->w.IRQ_Status |= (1<<23) | (1<<26) | (1<<27) | (1<<29); + + return ret; +} + +/* called when the port is closed */ +static void p2001_uart_ops_shutdown(struct uart_port *port) +{ + free_irq(port->irq, port); +} + +/* called whenever the port line settings need to be modified */ +static void p2001_uart_ops_set_termios(struct uart_port *port, struct termios *new, struct termios *old) +{ + unsigned int config; + unsigned long flags; + unsigned int prod, quot; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk); // min:0/max:port->uartclk + prod = 3; + quot = (port->uartclk * prod)/baud; + + /* interrupt level */ + config = (12 << 11) | (12 << 17); /* RXDHIGHWATER = 12, TXDLOWWATER = 12 */ + + /* data bits */ + switch (new->c_cflag & CSIZE) { + case CS5: + config |= (5 << 5); /* WORDLENGTH = 5 */ + break; + case CS6: + config |= (6 << 5); /* WORDLENGTH = 6 */ + break; + case CS7: + config |= (7 << 5); /* WORDLENGTH = 7 */ + break; + default: /* CS8 */ + config |= (8 << 5); /* WORDLENGTH = 8 */ + break; + } + + /* parity */ + if (new->c_cflag & PARENB) { + if (!(new->c_cflag & PARODD)) + config |= (1 << 2); /* PARITYMODE = 1 (Even Parity) */ + else + config |= (2 << 2); /* PARITYMODE = 2 (Odd Parity) */ + } + + /* stop bits */ + if (new->c_cflag & CSTOPB) + config |= (1 << 0); /* STOPBITAW = 1 (1 Stopbit) */ + + /* hardware flow control */ + if (new->c_cflag & CRTSCTS) { + config |= (1 << 10); /* USECTS = 1 */ + P2001_GPIO->PIN_MUX |= (1<<5); + } else { + P2001_GPIO->PIN_MUX &= ~(1<<5); + } + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, new->c_cflag, baud); + + port->read_status_mask = (1<<9); /* RXD_DATA_LOST */ + if (new->c_iflag & INPCK) + port->read_status_mask |= (1<<6); /* RxD_FIFO_PAR_ERR */ + if (new->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= (1<<7); /* RxD_BRK */ + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (new->c_iflag & IGNPAR) + port->ignore_status_mask |= (1<<6); /* RxD_FIFO_PAR_ERR */ + if (new->c_iflag & IGNBRK) { + port->ignore_status_mask |= (1<<7); /* RxD_BRK */ + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (new->c_iflag & IGNPAR) + port->ignore_status_mask |= (1<<9); /* RxD_LOST */ + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((new->c_cflag & CREAD) == 0) + port->ignore_status_mask |= (1<<3); /* RXD_DATA */ + + /* Set baud rate */ + P2001_UART->w.Baudrate = (quot<<16)+prod; + P2001_UART->w.Config = config; + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* power management: power the hardware down */ +#ifdef CONFIG_PM +static void p2001_uart_ops_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +{ +#warning "p2001_uart_ops_pm is not implemented." +} +#endif + +/* power management: power the hardware up */ +#ifdef CONFIG_PM +static int p2001_uart_ops_set_wake(struct uart_port *port, unsigned int state) +{ +#warning "p2001_uart_ops_set_wake is not implemented." +} +#endif + +/* + * Return a string describing the port type + */ +static const char *p2001_uart_ops_type(struct uart_port *port) +{ + return port->type == PORT_P2001 ? "P2001" : NULL; +} + +/* + * Release IO and memory resources used by + * the port. This includes iounmap if necessary. + */ +static void p2001_uart_ops_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 0x30); +} + +/* + * Request IO and memory resources used by the + * port. This includes iomapping the port if + * necessary. + */ +static int p2001_uart_ops_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, 0x30, p2001_uart_name) + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void p2001_uart_ops_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE && p2001_uart_ops_request_port(port) == 0) + port->type = PORT_P2001; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + */ +static int p2001_uart_ops_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_P2001) + ret = -EINVAL; + if (ser->irq != NO_IRQ) + ret = -EINVAL; + return ret; +} + +/* device specific ioctl calls */ +#if 0 +static int p2001_uart_ops_ioctl(struct uart_port *port, unsigned int, unsigned long) +{ +#warning "p2001_uart_ops_ioctl is not implemented." +} +#endif + + +static struct uart_ops p2001_uart_ops = { + .tx_empty = p2001_uart_ops_tx_empty, /* returns if the port transmitter is empty or not. */ + .set_mctrl = p2001_uart_ops_set_mctrl, /* sets a new value for the MCR UART register. */ + .get_mctrl = p2001_uart_ops_get_mctrl, /* gets the current MCR UART register value. */ + .stop_tx = p2001_uart_ops_stop_tx, /* stops the port from sending data. */ + .start_tx = p2001_uart_ops_start_tx, /* starts the port sending data. */ +// .send_xchar = p2001_uart_ops_send_xchar, /* tells the port to send the XOFF character to the host. */ + .stop_rx = p2001_uart_ops_stop_rx, /* stops receiving data. */ + .enable_ms = p2001_uart_ops_enable_ms, /* enables the modem status interrupts. */ + .break_ctl = p2001_uart_ops_break_ctl, /* sends the BREAK value over the port. */ + .startup = p2001_uart_ops_startup, /* called once each time the open call happens */ + .shutdown = p2001_uart_ops_shutdown, /* called when the port is closed */ + .set_termios = p2001_uart_ops_set_termios, /* called whenever the port line settings need to be modified */ +#ifdef CONFIG_PM + .pm = p2001_uart_ops_pm, /* power management: power the hardware down */ + .set_wake = p2001_uart_ops_set_wake, /* power management: power the hardware up */ +#endif + .type = p2001_uart_ops_type, /* Return a string describing the port type */ + .release_port = p2001_uart_ops_release_port, /* Release the region(s) being used by 'port' */ + .request_port = p2001_uart_ops_request_port, /* Request the region(s) being used by 'port' */ + .config_port = p2001_uart_ops_config_port, /* Configure/autoconfigure the port. */ + .verify_port = p2001_uart_ops_verify_port, /* Verify the new serial_struct (for TIOCSSERIAL). */ +// .ioctl = p2001_uart_ops_ioctl, /* device specific ioctl calls */ +}; + + + +/************************************************************************** + * CPU frequency scaling + **************************************************************************/ + +#ifdef CONFIG_CPU_FREQ + +/* + * Starts receiving data. + */ +static void p2001_uart_ops_start_rx(struct uart_port *port) +{ + if (!rx_enabled(port)) { + P2001_UART->w.IRQ_Status |= (1<<23); // RXD_DATA + rx_enabled(port) = 1; + } +} + +/* + * Here we define a transistion notifier so that we can update all of our + * ports' baud rate when the peripheral clock changes. + */ +static int p2001_uart_notifier(struct notifier_block *self, unsigned long phase, void *data) +{ + struct cpufreq_freqs *cf = data; + unsigned int prod, quot; + struct uart_port *port = &p2001_uart_port; + + if (phase == CPUFREQ_PRECHANGE) { + /* Stop transceiver */ + p2001_uart_ops_stop_rx(&p2001_uart_port); + p2001_uart_ops_stop_tx(&p2001_uart_port); + + while (!p2001_uart_ops_tx_empty(port)) + barrier(); + } + + if ((phase == CPUFREQ_POSTCHANGE) || + (phase == CPUFREQ_RESUMECHANGE)){ + /* Set new baud rate */ + port->uartclk = 1000 * cf->new / 8; // in MHz + prod = 3; + quot = (port->uartclk * prod)/baud; + P2001_UART->w.Baudrate = (quot<<16)+prod; + + /* Start transceiver */ + p2001_uart_ops_start_rx(&p2001_uart_port); + p2001_uart_ops_start_tx(&p2001_uart_port); + } + + return NOTIFY_OK; +} + +static struct notifier_block p2001_uart_nb = { &p2001_uart_notifier, NULL, 0 }; + +#endif /* CONFIG_CPU_FREQ */ + + + +/************************************************************************** + * Console + **************************************************************************/ + +#ifdef CONFIG_SERIAL_P2001_UART_CONSOLE + +/* the function used to print kernel messages */ +static void p2001_console_write(struct console *co, const char *s, unsigned int count) +{ + int i; + + for (i = 0; i < count; i++) { + while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF) + barrier(); + P2001_UART->w.TX[0] = s[i]; + if (s[i] == '\n') { + while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF) + barrier(); + P2001_UART->w.TX[0] = '\r'; + } + } +} + +/* the function is called when the console= command-line argument matches the name for this console structure. */ +static int __init p2001_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &p2001_uart_port; + int parity = 'n'; + int bits = 8; + int flow = 'n'; + + baud = DEFAULT_BAUD; + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + + +static struct console p2001_console = { + .name = "ttyS", /* the name of the console device is used to parse the console= command line option. */ + .write = p2001_console_write, /* the function used to print kernel messages */ +// .read = p2001_console_read, /* ??? */ + .device = uart_console_device, /* a function that returns the device number for the underlying tty device that is currently acting as a console */ +// .unblank = p2001_console_unblank, /* the function, if defined, is used to unblank the screen. */ + .setup = p2001_console_setup, /* the function is called when the console= command-line argument matches the name for this console structure. */ + .flags = CON_PRINTBUFFER, /* various console flags */ + .index = -1, /* the number of the device acting as a console in an array of devices. */ +// .cflag = 0, + .data = &p2001_uart_driver, +}; + +static int __init p2001_console_init(void) +{ + register_console(&p2001_console); + return 0; +} +console_initcall(p2001_console_init); +#endif + + + +/************************************************************************** + * Module functions + **************************************************************************/ + +static int __init p2001_uart_module_init(void) +{ + int ret; + + printk(version); + + ret = uart_register_driver(&p2001_uart_driver); + if (ret != 0) return ret; + + ret = uart_add_one_port(&p2001_uart_driver, &p2001_uart_port); + if (ret != 0) return ret; + +#ifdef CONFIG_CPU_FREQ + ret = cpufreq_register_notifier(&p2001_uart_nb, CPUFREQ_TRANSITION_NOTIFIER); + printk("p2001_uart: CPU frequency notifier registered\n"); +#endif + + return ret; +} + +static void __exit p2001_uart_module_exit(void) +{ +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&p2001_uart_nb, CPUFREQ_TRANSITION_NOTIFIER); + printk("p2001_uart: CPU frequency notifier unregistered\n"); +#endif + uart_remove_one_port(&p2001_uart_driver, &p2001_uart_port); + uart_unregister_driver(&p2001_uart_driver); +} + +module_init(p2001_uart_module_init); +module_exit(p2001_uart_module_exit); + +MODULE_AUTHOR("Tobias Lorenz"); +MODULE_DESCRIPTION("P2001 uart driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_atmel.c b/drivers/serial/serial_atmel.c new file mode 100644 index 00000000..bc9fa653 --- /dev/null +++ b/drivers/serial/serial_atmel.c @@ -0,0 +1,1882 @@ +/* serial port driver for the Atmel AT91 series builtin USARTs + * + * Copyright (C) 2000, 2001 Erik Andersen + * Copyright (C) 2004 Hyok S. Choi + * + * Based on: + * drivers/char/68302serial.c + * and also based on trioserial.c from Aplio, though this driver + * has been extensively changed since then. No author was + * listed in trioserial.c. + * + * Phil Wilshire 12/31/2002 Fixed multiple ^@ chars on TCSETA + * Hyok S. Choi 03/22/2004 2.6 port + */ + +/* Enable this to force this driver to always operate at 57600 */ +#undef FORCE_57600 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial_atmel.h" + +#define USE_INTS 1 + +static volatile struct atmel_usart_regs *usarts[AT91_USART_CNT] = { + (volatile struct atmel_usart_regs *) AT91_USART0_BASE, + (volatile struct atmel_usart_regs *) AT91_USART1_BASE +}; + +#define SERIAL_XMIT_SIZE PAGE_SIZE +#define RX_SERIAL_SIZE 256 + +static struct atmel_serial atmel_info[AT91_USART_CNT]; +static struct tty_struct *serial_table[AT91_USART_CNT]; +struct atmel_serial *atmel_consinfo = 0; + +#define UART_CLOCK (ARM_CLK/16) + +static struct work_struct serialpoll; + +#ifdef CONFIG_CONSOLE +extern wait_queue_head_t keypress_wait; +#endif + +struct tty_driver *serial_driver; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... DEBUG_INTR is bad to use when one of the zs + * lines is your console ;( + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define RS_ISR_PASS_LIMIT 256 + +#define _INLINE_ inline + +static inline int serial_paranoia_check(struct atmel_serial *info, + char *name, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct %s in %s\n"; + static const char *badinfo = + "Warning: null atmel_serial struct for %s in %s\n"; + + if (!info) { + printk(badinfo, name, routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, name, routine); + return 1; + } +#endif + return 0; +} + +static unsigned char * rx_buf_table[AT91_USART_CNT]; + +static unsigned char rx_buf1[RX_SERIAL_SIZE]; +static unsigned char rx_buf2[RX_SERIAL_SIZE]; + +/* Console hooks... */ + +static void serpoll(void *data); + +static void change_speed(struct atmel_serial *info); + +static char prompt0; +static void xmit_char(struct atmel_serial *info, char ch); +static void xmit_string(struct atmel_serial *info, char *p, int len); +static void start_rx(struct atmel_serial *info); +static void wait_EOT(volatile struct atmel_usart_regs *); +static void uart_init(struct atmel_serial *info); +static void uart_speed(struct atmel_serial *info, unsigned cflag); + +static void tx_enable(volatile struct atmel_usart_regs *uart); +static void rx_enable(volatile struct atmel_usart_regs *uart); +static void tx_disable(volatile struct atmel_usart_regs *uart); +static void rx_disable(volatile struct atmel_usart_regs *uart); +static void tx_stop(volatile struct atmel_usart_regs *uart); +static void tx_start(volatile struct atmel_usart_regs *uart); +static void rx_stop(volatile struct atmel_usart_regs *uart); +static void rx_start(volatile struct atmel_usart_regs *uart, int ints); +static void set_ints_mode(int yes, struct atmel_serial *info); +static irqreturn_t rs_interrupt(struct atmel_serial *info); +extern void show_net_buffers(void); +extern void hard_reset_now(void); +static void handle_termios_tcsets(struct termios * ptermios, struct atmel_serial * ptty); + +static int global; + +static void coucou1(void) +{ + global = 0; +} + +static void coucou2(void) +{ + global = 1; +} +static void _INLINE_ tx_enable(volatile struct atmel_usart_regs *uart) +{ + uart->ier = US_TXEMPTY; +} +static void _INLINE_ rx_enable(volatile struct atmel_usart_regs *uart) +{ + uart->ier = US_ENDRX | US_TIMEOUT; +} +static void _INLINE_ tx_disable(volatile struct atmel_usart_regs *uart) +{ + uart->idr = US_TXEMPTY; +} +static void _INLINE_ rx_disable(volatile struct atmel_usart_regs *uart) +{ + uart->idr = US_ENDRX | US_TIMEOUT; +} +static void _INLINE_ tx_stop(volatile struct atmel_usart_regs *uart) +{ + tx_disable(uart); + uart->tcr = 0; + uart->cr = US_TXDIS; +} +static void _INLINE_ tx_start(volatile struct atmel_usart_regs *uart) +{ + tx_enable(uart); + uart->cr = US_TXEN; +} +static void _INLINE_ rx_stop(volatile struct atmel_usart_regs *uart) +{ + rx_disable(uart); + uart->rtor = 0; + // PSW fixes slew of ^@ chars on a TCSETA ioctl + //uart->rcr = 0; + uart->cr = US_RXDIS; +} +static void _INLINE_ rx_start(volatile struct atmel_usart_regs *uart, int ints) +{ + uart->cr = US_RXEN | US_STTO; + uart->rtor = 20; + if (ints) { + rx_enable(uart); + } +} +static void _INLINE_ reset_status(volatile struct atmel_usart_regs *uart) +{ + uart->cr = US_RSTSTA; +} +static void set_ints_mode(int yes, struct atmel_serial *info) +{ + info->use_ints = yes; +// FIXME: check +#if 0 + (yes) ? unmask_irq(info->irq) : mask_irq(info->irq); +#endif +} + +#ifdef US_RTS +static void atmel_cts_off(struct atmel_serial *info) +{ + volatile struct atmel_usart_regs *uart; + + uart = info->usart; + uart->mc &= ~(unsigned long) US_RTS; + info->cts_state = 0; +} +static void atmel_cts_on(struct atmel_serial *info) +{ + volatile struct atmel_usart_regs *uart; + + uart = info->usart; + uart->mc |= US_RTS; + info->cts_state = 1; +} +/* Sets or clears DTR/RTS on the requested line */ +static inline void atmel_rtsdtr(struct atmel_serial *ss, int set) +{ + volatile struct atmel_usart_regs *uart; + + uart = ss->usart; + if (set) { + uart->mc |= US_DTR | US_RTS; + } else { + uart->mc &= ~(unsigned long) (US_DTR | US_RTS); + } + return; +} +#endif /* US_RTS */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_stop")) + return; + + local_irq_save(flags); + tx_stop(info->usart); + rx_stop(info->usart); + local_irq_restore(flags); +} + +static void rs_put_char(struct atmel_serial *info, char ch) +{ + unsigned long flags; + + local_irq_save(flags); + xmit_char(info, ch); + wait_EOT(info->usart); + local_irq_restore(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_start")) + return; + + local_irq_save(flags); + tx_start(info->usart); + rx_start(info->usart, info->use_ints); + /* FIXME */ +// start_rx(info); + local_irq_restore(flags); +} + +/* Drop into either the boot monitor or kadb upon receiving a break + * from keyboard/console input. + */ +static void batten_down_hatches(void) +{ + /* Drop into the debugger */ +} + +static _INLINE_ void status_handle(struct atmel_serial *info, unsigned long status) +{ +#if 0 + if (status & DCD) { + if ((info->tty->termios->c_cflag & CRTSCTS) && + ((info->curregs[3] & AUTO_ENAB) == 0)) { + info->curregs[3] |= AUTO_ENAB; + info->pendregs[3] |= AUTO_ENAB; + write_zsreg(info->atmel_channel, 3, info->curregs[3]); + } + } else { + if ((info->curregs[3] & AUTO_ENAB)) { + info->curregs[3] &= ~AUTO_ENAB; + info->pendregs[3] &= ~AUTO_ENAB; + write_zsreg(info->atmel_channel, 3, info->curregs[3]); + } + } +#endif + /* Whee, if this is console input and this is a + * 'break asserted' status change interrupt, call + * the boot prom. + */ + if ((status & US_RXBRK) && info->break_abort) + batten_down_hatches(); + + /* XXX Whee, put in a buffer somewhere, the status information + * XXX whee whee whee... Where does the information go... + */ + reset_status(info->usart); + return; +} + +static _INLINE_ void receive_chars(struct atmel_serial *info, unsigned long status) +{ + int count; + volatile struct atmel_usart_regs *uart = info->usart; + char *rxp, ch, flag; + struct tty_struct *tty = info->tty; + + if (!(info->flags & S_INITIALIZED)) + return; + count = RX_SERIAL_SIZE - uart->rcr; + // hack to receive chars by polling only BD fields + if (!count) { + return; + } + + if (!tty) + goto clear_and_exit; + +#if 0 + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + schedule_work(&tty->flip.work); + + if ((count + tty->flip.count) >= TTY_FLIPBUF_SIZE) { +#ifdef US_RTS + atmel_cts_off(info); +#endif + serialpoll.data = (void *) info; + schedule_work(&serialpoll); + } + memset(tty->flip.flag_buf_ptr, 0, count); + memcpy(tty->flip.char_buf_ptr, info->rx_buf, count); + tty->flip.char_buf_ptr += count; + + if (status & US_PARE) + *(tty->flip.flag_buf_ptr - 1) = TTY_PARITY; + else if (status & US_OVRE) + *(tty->flip.flag_buf_ptr - 1) = TTY_OVERRUN; + else if (status & US_FRAME) + *(tty->flip.flag_buf_ptr - 1) = TTY_FRAME; + + tty->flip.count += count; +#endif +#if 1 + rxp = info->rx_buf; + for (; (count > 0); count--) { + + ch = *rxp++; + flag = TTY_NORMAL; + if (status & US_PARE) + flag = TTY_PARITY; + else if (status & US_OVRE) + flag = TTY_OVERRUN; + else if (status & US_FRAME) + flag = TTY_FRAME; + + + tty_insert_flip_char(tty, ch, flag); + } +#endif + + tty_schedule_flip(tty); + + clear_and_exit: + start_rx(info); + return; +} + +static _INLINE_ void transmit_chars(struct atmel_serial *info) +{ + if (info->x_char) { + /* Send next char */ + xmit_char(info, info->x_char); + info->x_char = 0; + goto clear_and_return; + } + + if ((info->xmit_cnt <= 0) || info->tty->stopped) { + /* That's peculiar... */ + tx_stop(info->usart); + goto clear_and_return; + } + + if (info->xmit_tail + info->xmit_cnt < SERIAL_XMIT_SIZE) { + xmit_string(info, info->xmit_buf + info->xmit_tail, + info->xmit_cnt); + info->xmit_tail = + (info->xmit_tail + info->xmit_cnt) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt = 0; + } else { + coucou1(); + xmit_string(info, info->xmit_buf + info->xmit_tail, + SERIAL_XMIT_SIZE - info->xmit_tail); + //xmit_string(info, info->xmit_buf, info->xmit_tail + info->xmit_cnt - SERIAL_XMIT_SIZE); + info->xmit_cnt = + info->xmit_cnt - (SERIAL_XMIT_SIZE - info->xmit_tail); + info->xmit_tail = 0; + } + + if (info->xmit_cnt < WAKEUP_CHARS) + schedule_work(&info->tqueue); + + if (info->xmit_cnt <= 0) { + //tx_stop(info->usart); + goto clear_and_return; + } + + clear_and_return: + /* Clear interrupt (should be auto) */ + return; +} + +/* + * This is the serial driver's generic interrupt routine + */ +static irqreturn_t rs_interrupta(int irq, void *dev_id, struct pt_regs *regs) +{ + return rs_interrupt(&atmel_info[0]); +} +static irqreturn_t rs_interruptb(int irq, void *dev_id, struct pt_regs *regs) +{ + return rs_interrupt(&atmel_info[1]); +} +static irqreturn_t rs_interrupt(struct atmel_serial *info) +{ + unsigned long status; + + status = info->usart->csr; + if (status & (US_ENDRX | US_TIMEOUT)) { + receive_chars(info, status); + } + if (status & (US_TXEMPTY)) { + transmit_chars(info); + } + status_handle(info, status); + +#ifdef US_RTS + if (!info->cts_state) { + if (info->tty->flip.count < TTY_FLIPBUF_SIZE - RX_SERIAL_SIZE) { + atmel_cts_on(info); + } + } +#endif + if (!info->use_ints) { + serialpoll.data = (void *) info; + schedule_work(&serialpoll); + } + return IRQ_HANDLED; +} +static void serpoll(void *data) +{ + struct atmel_serial *info = data; + + rs_interrupt(info); +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + + +static void do_softint(void *private_) +{ + struct atmel_serial *info = (struct atmel_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; +#if 0 // FIXME - CHECK + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); + } +#endif +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct atmel_serial *info = (struct atmel_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work at all for 16450's, as a sun has a Z8530. + */ +#if 0 +static void rs_timer(void) +{ + panic("rs_timer called\n"); + return; +} +#endif + +static unsigned long calcCD(unsigned long br) +{ + return (UART_CLOCK / br); +} + +static void uart_init(struct atmel_serial *info) +{ + volatile struct atmel_usart_regs *uart; + + if (info) { + uart = info->usart; + } else { + uart = usarts[0]; + } + + /* Reset the USART */ + uart->cr = US_TXDIS | US_RXDIS | US_RSTTX | US_RSTRX; + /* clear Rx receive and Tx sent counters */ + uart->rcr = 0; + uart->tcr = 0; + + /* Disable interrups till we say we want them */ + tx_disable(info->usart); + rx_disable(info->usart); + + /* Set the serial port into a safe sane state */ + uart->mr = US_USCLKS(0) | US_CLK0 | US_CHMODE(0) | US_NBSTOP(0) | + US_PAR(4) | US_CHRL(3); + +#ifndef FORCE_57600 + uart->brgr = calcCD(9600); +#else + uart->brgr = calcCD(57600); +#endif + + uart->rtor = 20; // timeout = value * 4 *bit period + uart->ttgr = 0; // no guard time + uart->rcr = 0; + uart->rpr = 0; + uart->tcr = 0; + uart->tpr = 0; +#ifdef US_RTS + uart->mc = 0; +#endif +} + +/* It is the responsibilty of whoever calls this function to be sure + * that that have called + * tx_stop(uart); rx_stop(uart); + * before calling the function. Failure to do this will cause messy + * things to happen. You have been warned. */ +static void uart_speed(struct atmel_serial *info, unsigned cflag) +{ + unsigned baud = info->baud; + volatile struct atmel_usart_regs *uart = info->usart; + + // disable tx and rx + uart->cr = US_TXDIS | US_RXDIS; + + // disable interrupts + tx_disable(uart); + rx_disable(uart); + +#ifndef FORCE_57600 + uart->brgr = calcCD(baud); +#else + uart->brgr = calcCD(57600); +#endif +/* FIXME */ +#if 0 + /* probably not needed */ + uart->US_RTOR = 20; // timeout = value * 4 *bit period + uart->US_TTGR = 0; // no guard time + uart->US_RPR = 0; + uart->US_RCR = 0; + uart->US_TPR = 0; + uart->US_TCR = 0; +#endif + + +/* FIXME */ +#if 0 + uart->mc = 0; + if (cflag != 0xffff) { + uart->mr = US_USCLKS(0) | US_CLK0 | US_CHMODE(0) | US_NBSTOP(0) | + US_PAR(0); + + if ((cflag & CSIZE) == CS8) + uart->mr |= US_CHRL(3); // 8 bit char + else + uart->mr |= US_CHRL(2); // 7 bit char + + if (cflag & CSTOPB) + uart->mr |= US_NBSTOP(2); // 2 stop bits + + if (!(cflag & PARENB)) + uart->mr |= US_PAR(4); // parity disabled + else if (cflag & PARODD) + uart->mr |= US_PAR(1); // odd parity + } +#endif + +/* FIXME */ +#if 0 + // enable tx and rx + uart->cr = US_TXEN | US_RXEN; + + // enable interrupts + tx_enable(); + rx_enable(); +#endif + tx_start(uart); + start_rx(info); +} + +static void wait_EOT(volatile struct atmel_usart_regs *uart) +{ + // make sure tx is enabled + uart->cr = US_TXEN; + + // wait until all chars sent FIXME - is this sane ? + while (1) { + if (uart->csr & US_TXEMPTY) + break; + } +} +static int startup(struct atmel_serial *info) +{ + unsigned long flags; + + if (info->flags & S_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + if (!info->rx_buf) { + //info->rx_buf = (unsigned char *) ))__get_free_page(GFP_KERNEL); + //info->rx_buf = rx_buf1; + if (!info->rx_buf) + return -ENOMEM; + } + local_irq_save(flags); +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); +#endif + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + + uart_init(info); + //set_ints_mode(0, info); + change_speed(info); + info->flags |= S_INITIALIZED; + local_irq_restore(flags); + return 0; +} + +/* + * 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 shutdown(struct atmel_serial *info) +{ + unsigned long flags; + + tx_disable(info->usart); + rx_disable(info->usart); + rx_stop(info->usart); /* All off! */ + if (!(info->flags & S_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....\n", info->line, + info->irq); +#endif + + local_irq_save(flags); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~S_INITIALIZED; + local_irq_restore(flags); +} + +/* rate = 1036800 / ((65 - prescale) * (1<tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + + // disable tx and rx + info->usart->cr = US_TXDIS | US_RXDIS; + + /* First disable the interrupts */ + tx_stop(info->usart); + rx_stop(info->usart); + + /* set the baudrate */ + i = cflag & CBAUD; + + info->baud = baud_table[i]; + uart_speed(info, cflag); + tx_start(info->usart); + rx_start(info->usart, info->use_ints); + + // enable tx and rx + info->usart->cr = US_TXEN | US_RXEN; + + return; +} + +static void start_rx(struct atmel_serial *info) +{ + volatile struct atmel_usart_regs *uart = info->usart; + + rx_stop(uart); +/* FIXME - rehnberg + if (info->rx_buf == rx_buf1) { + info->rx_buf = rx_buf2; + } else { + info->rx_buf = rx_buf1; + } +*/ + uart->rpr = (unsigned long) info->rx_buf; + uart->rcr = (unsigned long) RX_SERIAL_SIZE; + rx_start(uart, info->use_ints); +} +static void xmit_char(struct atmel_serial *info, char ch) +{ + prompt0 = ch; + xmit_string(info, &prompt0, 1); +} +static void xmit_string(struct atmel_serial *info, char *p, int len) +{ + info->usart->tcr = 0; + info->usart->tpr = (unsigned long) p; + info->usart->tcr = (unsigned long) len; + tx_start(info->usart); +} + +/* + * atmel_console_print is registered for printk. + */ +int atmel_console_initialized; + +static void init_console(struct atmel_serial *info) +{ + memset(info, 0, sizeof(struct atmel_serial)); + +#ifdef CONFIG_SWAP_ATMEL_PORTS + info->usart = (volatile struct atmel_usart_regs *) AT91_USART1_BASE; + info->irqmask = AIC_URT1; + info->irq = IRQ_USART1; +#else + info->usart = (volatile struct atmel_usart_regs *) AT91_USART0_BASE; + info->irqmask = 1<irq = IRQ_USART0; +#endif + info->tty = 0; + info->port = 0; + info->use_ints = 0; + info->cts_state = 1; + info->is_cons = 1; + atmel_console_initialized = 1; +} + + +void console_print_atmel(const char *p) +{ + char c; + struct atmel_serial *info; + +#ifdef CONFIG_SWAP_ATMEL_PORTS + info = &atmel_info[1]; +#else + info = &atmel_info[0]; +#endif + + if (!atmel_console_initialized) { + init_console(info); + uart_init(info); + info->baud = 9600; + tx_stop(info->usart); + rx_stop(info->usart); + uart_speed(info, 0xffff); + tx_start(info->usart); + rx_start(info->usart, info->use_ints); + } + + while ((c = *(p++)) != 0) { + if (c == '\n') + rs_put_char(info, '\r'); + rs_put_char(info, c); + } + + /* Comment this if you want to have a strict interrupt-driven output */ +#if 0 + if (!info->use_ints) + rs_fair_output(info); +#endif + + return; +} + +static void rs_set_ldisc(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) + return; + + info->is_cons = (tty->termios->c_line == N_TTY); + + printk("ttyS%d console mode %s\n", info->line, + info->is_cons ? "on" : "off"); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) + return; + if (!info->use_ints) { + for (;;) { + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) return; + + /* Enable transmitter */ + local_irq_save(flags); + tx_start(info->usart); + } + } else { + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) return; + + /* Enable transmitter */ + local_irq_save(flags); + tx_start(info->usart); + } + + if (!info->use_ints) + wait_EOT(info->usart); + /* Send char */ + xmit_char(info, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt--; + + local_irq_restore(flags); +} + +extern void console_printn(const char *b, int count); + +static int rs_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + int c, total = 0; + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + local_save_flags(flags); + while (1) { + local_irq_disable(); + c = min(count, (int) min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + local_irq_restore(flags); + + if (c <= 0) + break; + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + + local_irq_disable(); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + local_irq_restore(flags); + + buf += c; + count -= c; + total += c; + } + + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + /* Enable transmitter */ + + local_irq_disable(); + /*printk("Enabling transmitter\n"); */ + + if (!info->use_ints) { + while (info->xmit_cnt) { + wait_EOT(info->usart); + /* Send char */ + xmit_char(info, info->xmit_buf[info->xmit_tail++]); + wait_EOT(info->usart); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt--; + } + } else { + if (info->xmit_cnt) { + /* Send char */ + wait_EOT(info->usart); + if (info->xmit_tail + info->xmit_cnt < SERIAL_XMIT_SIZE) { + xmit_string(info, info->xmit_buf + info->xmit_tail, + info->xmit_cnt); + info->xmit_tail = + (info->xmit_tail + + info->xmit_cnt) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt = 0; + } else { + coucou2(); + xmit_string(info, info->xmit_buf + info->xmit_tail, + SERIAL_XMIT_SIZE - info->xmit_tail); + //xmit_string(info, info->xmit_buf, info->xmit_tail + info->xmit_cnt - SERIAL_XMIT_SIZE); + info->xmit_cnt = + info->xmit_cnt - (SERIAL_XMIT_SIZE - info->xmit_tail); + info->xmit_tail = 0; + } + } + } + } else { + /*printk("Skipping transmit\n"); */ + } + +#if 0 + printk("Enabling stuff anyhow\n"); + tx_start(0); + + if (SCC_EOT(0, 0)) { + printk("TX FIFO empty.\n"); + /* Send char */ + atmel_xmit_char(info->usart, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt--; + } +#endif + + local_irq_restore(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->name, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) + return; + local_irq_save(flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_restore(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line (do this atomic) */ +} + +static void rs_unthrottle(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line (do this atomic) */ +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct atmel_serial *info, + struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + copy_to_user(retinfo, &tmp, sizeof(*retinfo)); + return 0; +} + +static int set_serial_info(struct atmel_serial *info, + struct serial_struct *new_info) +{ + struct serial_struct new_serial; + struct atmel_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + copy_from_user(&new_serial, new_info, sizeof(new_serial)); + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~S_USR_MASK) != + (info->flags & ~S_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~S_USR_MASK) | + (new_serial.flags & S_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~S_FLAGS) | + (new_serial.flags & S_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + + check_and_exit: + //retval = startup(info); + change_speed(info); + retval = 0; + return retval; +} + +/* + * 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 int get_lsr_info(struct atmel_serial *info, unsigned int *value) +{ + unsigned char status; + unsigned long flags; + + local_irq_save(flags); + status = info->usart->csr; + status &= US_TXEMPTY; + local_irq_restore(flags); + put_user(status, value); + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break(struct atmel_serial *info, int duration) +{ + unsigned long flags; + if (!info->port) return; + + current->state = TASK_INTERRUPTIBLE; + local_irq_save(flags); + info->usart->cr = US_STTBRK; + if (!info->use_ints) { + while (US_TXRDY != (info->usart->csr & US_TXRDY)) { + ; // this takes max 2ms at 9600 + } + info->usart->cr = US_STPBRK; + } + local_irq_restore(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + int retval; + + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ / 4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); + return 0; + case TIOCGSOFTCAR: + error = access_ok(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + arg = get_user(arg,(unsigned long *) arg); + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + return 0; + case TIOCGSERIAL: + error = access_ok(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct)); + if (error) + return error; + return get_serial_info(info, (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + error = access_ok(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + else + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + error = access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct atmel_serial)); + if (error) + return error; + copy_to_user((struct atmel_serial *) arg, info, + sizeof(struct atmel_serial)); + return 0; + + case TCSETS: + handle_termios_tcsets((struct termios *)arg, info); + // return set_serial_info(info, (struct serial_struct *) arg); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void handle_termios_tcsets(struct termios * ptermios, struct atmel_serial * pinfo ) +{ + /* + * hmmmm.... + */ + if (pinfo->tty->termios->c_cflag != ptermios->c_cflag) + pinfo->tty->termios->c_cflag = ptermios->c_cflag; + change_speed(pinfo); +} + +static void rs_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file *filp) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + return; + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + local_irq_restore(flags); + return; + } +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttyS%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + local_irq_restore(flags); + return; + } + // closing port so disable interrupts + set_ints_mode(0, info); + + info->flags |= S_CLOSING; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != S_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close) (tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open) (tty); + } +#endif + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(S_NORMAL_ACTIVE | S_CALLOUT_ACTIVE | S_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct atmel_serial *info = (struct atmel_serial *) tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~S_NORMAL_ACTIVE; + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct atmel_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & S_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= S_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttyS%d, count = %d\n", + info->line, info->count); +#endif + info->count--; + info->blocked_open++; + while (1) { +#ifdef US_RTS + local_irq_save(flags); + atmel_rtsdtr(info, 1); + local_irq_restore(flags); +#endif + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & S_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & S_CLOSING) && do_clocal) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= S_NORMAL_ACTIVE; + if (!info->use_ints) { + serialpoll.data = (void *) info; + schedule_work(&serialpoll); + } + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its S structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file *filp) +{ + struct atmel_serial *info; + int retval, line; + + line = tty->index; + + // check if line is sane + if (line < 0 || line >= AT91_USART_CNT) + return -ENODEV; + + info = &atmel_info[line]; + if (serial_paranoia_check(info, tty->name, "rs_open")) + return -ENODEV; + + info->count++; + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + set_ints_mode(1, info); + + retval = startup(info); + if (retval) + return retval; + + return block_til_ready(tty, filp, info); +} + + +static struct irqaction irq_usart0 = { + .handler = rs_interrupta, + .name = "usart0", +}; +static struct irqaction irq_usart1 = { + .handler = rs_interruptb, + .name = "usart1", +}; + +static void interrupts_init(void) +{ + setup_irq(IRQ_USART0, &irq_usart0); + setup_irq(IRQ_USART1, &irq_usart1); +} + +static void show_serial_version(void) +{ + printk("Atmel USART driver version 0.99\n"); +} + +static struct tty_operations rs_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .flush_buffer = rs_flush_buffer, + .ioctl = rs_ioctl, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, + .set_termios = rs_set_termios, + .stop = rs_stop, + .start = rs_start, + .hangup = rs_hangup, + .set_ldisc = rs_set_ldisc, +}; + +/* rs_init inits the driver */ +static int __init +rs_atmel_init(void) +{ + struct atmel_serial *info; + unsigned long flags; + int i; + + /* initialise PIO for serial port */ + HW_AT91_USART_INIT + + serial_driver = alloc_tty_driver(2); + if (!serial_driver) + return -ENOMEM; + + // FIXME - do this right + rx_buf_table[0] = rx_buf1; + rx_buf_table[1] = rx_buf2; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + + // set the tty_struct pointers to NULL to let the layer + // above allocate the structs. + for (i=0; i < AT91_USART_CNT; i++) + serial_table[i] = NULL; + + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &rs_ops); + + if (tty_register_driver(serial_driver)) { + put_tty_driver(serial_driver); + printk(KERN_ERR "Couldn't register serial driver\n"); + return -ENOMEM; + } + + local_irq_save(flags); + for (i = 0; i < 2; i++) { + info = &atmel_info[i]; + info->magic = SERIAL_MAGIC; + info->usart = usarts[i]; + info->tty = 0; + info->irqmask = (i) ? (1<irq = (i) ? IRQ_USART1 : IRQ_USART0; +#ifdef CONFIG_SWAP_ATMEL_PORTS + info->port = (i) ? 2 : 1; + info->line = !i; +#ifdef CONFIG_ATMEL_CONSOLE + info->is_cons = i; +#else + info->is_cons = 0; +#endif +#else + info->port = (i) ? 1 : 2; + info->line = i; +#ifdef CONFIG_ATMEL_CONSOLE + info->is_cons = !i; +#else + info->is_cons = 0; +#endif +#endif +#ifdef CONFIG_CONSOLE_ON_SC28L91 + info->line += 1; +#endif + set_ints_mode(0, info); + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->cts_state = 1; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->rx_buf = rx_buf_table[i]; + + printk("%s%d at 0x%p (irq = %d)", serial_driver->name, info->line, + info->usart, info->irq); + printk(" is a builtin Atmel APB USART\n"); + } + + // FIXME + info->usart->cr = 0x1ac; // reset, disable + info->usart->idr = 0xffffffff; // disable all interrupts + info->usart->tcr = 0; // stop transmit + info->usart->rcr = 0; // stop receive + + interrupts_init(); + + local_irq_restore(flags); + // hack to do polling + serialpoll.func = serpoll; + serialpoll.data = 0; + + return 0; +} + +module_init(rs_atmel_init); + +#if 0 +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +/* SPARC: Unused at this time, just here to make things link. */ +static int register_serial(struct serial_struct *req) +{ + return -1; +} + +static void unregister_serial(int line) +{ + return; +} + +static void dbg_putc(int ch) +{ + static char tmp[2]; +#define US_TPR (0x38) /* Transmit Pointer Register */ +#define US_TCR (0x3C) /* Transmit Counter Register */ + + tmp[0] = ch; + + outl_t((unsigned long) tmp, (USART0_BASE + US_TPR) ); + outl_t(1, (USART0_BASE + US_TCR) ); + + while (inl_t((USART0_BASE + US_TCR) )) { + } +} + +static void dbg_print(const char *str) +{ + const char *p; + + for (p = str; *p; p++) { + if (*p == '\n') { + dbg_putc('\r'); + } + dbg_putc(*p); + } +} + +static void dbg_printk(const char *fmt, ...) +{ + char tmp[256]; + va_list args; + + va_start(args, fmt); + vsprintf(tmp, fmt, args); + va_end(args); + dbg_print(tmp); +} + +static void rs_atmel_print(const char *str) +{ + dbg_printk(str); +} + +static void dump_a(unsigned long a, unsigned int s) +{ + unsigned long q; + + for (q = 0; q < s; q++) { + if (q % 16 == 0) { + dbg_printk("%08X: ", q + a); + } + if (q % 16 == 7) { + dbg_printk("%02X-", *(unsigned char *) (q + a)); + } else { + dbg_printk("%02X ", *(unsigned char *) (q + a)); + } + if (q % 16 == 15) { + dbg_printk(" :\n"); + } + } + if (q % 16) { + dbg_printk(" :\n"); + } +} +#endif + +int atmel_console_setup(struct console *cp, char *arg) +{ + if (!cp) + return(-1); + HW_AT91_USART_INIT + return 0; +} + +static struct tty_driver *atmel_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + +void atmel_console_write (struct console *co, const char *str, + unsigned int count) +{ + struct atmel_serial *info; + +#ifdef CONFIG_SWAP_ATMEL_PORTS + info = &atmel_info[1]; +#else + info = &atmel_info[0]; +#endif + + if (!atmel_console_initialized) { + init_console(info); + uart_init(info); + info->baud = 9600; + tx_stop(info->usart); + rx_stop(info->usart); + uart_speed(info, 0xffff); + tx_start(info->usart); + rx_start(info->usart, info->use_ints); + } + + while (count--) { + if (*str == '\n') + rs_put_char(info,'\r'); + rs_put_char(info, *str++ ); + } +} + +static struct console atmel_driver = { + name: "ttyS", + write: atmel_console_write, + device: atmel_console_device, + setup: atmel_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + + +static int __init atmel_console_init(void) +{ + register_console(&atmel_driver); + return 0; +} + +console_initcall(atmel_console_init); diff --git a/drivers/serial/serial_atmel.h b/drivers/serial/serial_atmel.h new file mode 100644 index 00000000..21c90029 --- /dev/null +++ b/drivers/serial/serial_atmel.h @@ -0,0 +1,124 @@ +/* serial-atmel.h: Definitions for the Atmel serial driver. + * + * Copyright (C) 1998 Kenneth Albanowski , + * D. Jeff Dionne , + * The Silver Hammer Group, Ltd. + * Copyright (C) 2004 Hyok S. Choi + * 2.6 port + * + * Based on: + * + * drivers/char/68328serial.h + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _ATMEL_SERIAL_H +#define _ATMEL_SERIAL_H + +#include +#include + +/* + * 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 */ + +#define RS_EVENT_WRITE_WAKEUP 0 +#define SERIAL_MAGIC 0x5301 + +/* Software state per channel */ + +/* + * 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 atmel_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 irqmask; + int flags; /* defined in tty.h */ + int type; /* UART type */ + int use_ints; + volatile struct atmel_usart_regs *usart; + int cts_state; + 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; + unsigned char *rx_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; +}; + +#endif /* !(_ATMEL_SERIAL_H) */ diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index c67b05e9..8804e363 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -36,6 +36,12 @@ #include #include +#if 1 // add by Victor Yu. 02-09-2007 +#include +#include +#include +#include +#endif #undef DEBUG #ifdef DEBUG @@ -1051,6 +1057,61 @@ static int uart_get_count(struct uart_state *state, return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; } +#if 1 // add by Victor Yu. 02-09-2007 +#define PIO(x) (1<> 16; + if ( HZ <= 1000 ) + ms = ms / (1000/HZ); + else + ms = (ms * 1000) / (1000000/HZ); + if ( ms <= 0 ) + ms = 1; + + if ( readyledflag == 0 ) { // add by Victor Yu. 07-26-2007 + // enable beeper GPIO output + mcpu_gpio_mp_set(BEEPER_IO); + mcpu_gpio_inout(BEEPER_IO, MCPU_GPIO_OUTPUT); + + /* light ready led after jump into user space */ + mcpu_gpio_mp_set(SW_READY_LED); + mcpu_gpio_inout(SW_READY_LED, MCPU_GPIO_OUTPUT); + mcpu_gpio_set(SW_READY_LED, MCPU_GPIO_LOW); + readyledflag = 1; + } + + spin_lock(&beeplock); + /* sound on */ + mcpu_gpio_set(BEEPER_IO, MCPU_GPIO_HIGH); + ss = ms; + ms += jiffies ; + while( !time_after(jiffies,ms)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ss); + if (signal_pending(current)) + break; + ss = ms - jiffies; + } + /* sound off */ + mcpu_gpio_set(BEEPER_IO, MCPU_GPIO_LOW); + spin_unlock(&beeplock); +} +#endif + /* * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here. */ @@ -1068,6 +1129,12 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, * These ioctls don't rely on the hardware to be present. */ switch (cmd) { +#if 1 // add by Victor Yu. 02-09-2007 + case KDMKTONE: + beep_sound(arg) ; + ret = 0; + break; +#endif case TIOCGSERIAL: ret = uart_get_info(state, uarg); break; diff --git a/drivers/serial/serial_dm270.c b/drivers/serial/serial_dm270.c new file mode 100644 index 00000000..51bb6ea7 --- /dev/null +++ b/drivers/serial/serial_dm270.c @@ -0,0 +1,944 @@ +/* + * linux/drivers/serial/serial_dm270.c + * + * Driver for DM270 serial ports + * + * Copyright (c) 2004 Chee Tim Loh + * + * Based on drivers/char/serial_s3c4510b.c + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Based on drivers/char/serial_amba.c + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define UART_NR 2 +#define UART_DRIVER_NAME "TI TMS320DM270 Internal UART" +#define UART_TYPE "DM270_UART" +#define UART_DEFAULT_BAUD 38400 +#define UART_ISR_PASS_LIMIT 256 + +#define CONSOLE_DEFAULT_BAUD 38400 /* 38,400 buad */ +#define CONSOLE_DEFAULT_BITS 8 /* 8 data bits */ +#define CONSOLE_DEFAULT_PARITY 'n' /* no parity */ +#define CONSOLE_DEFAULT_FLOW 'n' /* no flow control */ + +struct dm270_uart_port { + struct uart_port uport; + unsigned short msr; +/* unsigned short dtrr_break_flag;*/ +}; + +static void dm270_uart_stop_tx(struct uart_port *uport, unsigned int tty_stop); + +/** + ** + ** Platform specific functions + ** Note: These definitions and routines will surely need to change if porting + ** this driver to another platform. + ** + **/ + +static inline unsigned short +dm270_uart_hwin(struct uart_port *uport, unsigned long offset) +{ + return inw(uport->iobase + offset); +} + +static inline void +dm270_uart_hwout(struct uart_port *uport, unsigned long offset, unsigned short value) +{ + outw(value, uport->iobase + offset); +} + +static void +dm270_uart_hwreset(struct uart_port *uport) +{ + unsigned short reg; + + /* Disable clock to UART. */ + reg = inw(DM270_CLKC_MOD2); + outw((reg & ~(DM270_CLKC_MOD2_CUAT << uport->line)), DM270_CLKC_MOD2); + + /* Select CLK_ARM as UART clock source */ + reg = inw(DM270_CLKC_CLKC); + outw((reg & ~(DM270_CLKC_CLKC_CUAS << uport->line)), DM270_CLKC_CLKC); + + /* Enable clock to UART. */ + reg = inw(DM270_CLKC_MOD2); + outw((reg | (DM270_CLKC_MOD2_CUAT << uport->line)), DM270_CLKC_MOD2); + + if (uport->line == 1) { +#ifndef CONFIG_SERIAL_DM270_BOOT_CTRL_UART1 + /* Configure GIO23 & GIO24 as RXD1 & TXD1 respectively */ + reg = inw(DM270_GIO_FSEL0); + outw(reg | DM270_GIO_FSEL_RXD1, DM270_GIO_FSEL0); + reg = inw(DM270_GIO_FSEL1); + outw(reg | DM270_GIO_FSEL_TXD1, DM270_GIO_FSEL1); +#endif + } +} + +static inline void +dm270_uart_disable_tx_int(struct uart_port *uport) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr &= ~DM270_UART_MSR_TFTIE; + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_disable_rx_int(struct uart_port *uport) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr &= ~(DM270_UART_MSR_TOIC_MASK | DM270_UART_MSR_REIE | + DM270_UART_MSR_RFTIE); + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_enable_tx_int(struct uart_port *uport) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr |= DM270_UART_MSR_TFTIE; + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_enable_rx_int(struct uart_port *uport) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr = (dm270_uport->msr & ~DM270_UART_MSR_TOIC_MASK) | + (DM270_UART_MSR_TIMEOUT_7 | DM270_UART_MSR_REIE | + DM270_UART_MSR_RFTIE); + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_disable_ints(struct uart_port *uport, unsigned short *msr) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + *msr = dm270_uport->msr & (DM270_UART_MSR_TOIC_MASK | DM270_UART_MSR_REIE | + DM270_UART_MSR_TFTIE | DM270_UART_MSR_RFTIE); + dm270_uport->msr &= ~(DM270_UART_MSR_TOIC_MASK | DM270_UART_MSR_REIE | + DM270_UART_MSR_TFTIE | DM270_UART_MSR_RFTIE); + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_restore_ints(struct uart_port *uport, unsigned short msr) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr = (dm270_uport->msr & ~(DM270_UART_MSR_TOIC_MASK | DM270_UART_MSR_REIE | + DM270_UART_MSR_TFTIE | DM270_UART_MSR_RFTIE)) | + (msr & (DM270_UART_MSR_TOIC_MASK | DM270_UART_MSR_REIE | + DM270_UART_MSR_TFTIE | DM270_UART_MSR_RFTIE)); + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_clear_fifos(struct uart_port *uport) +{ + dm270_uart_hwout(uport, DM270_UART_TFCR, + dm270_uart_hwin(uport, DM270_UART_TFCR) | DM270_UART_TFCR_CLEAR); + dm270_uart_hwout(uport, DM270_UART_RFCR, + dm270_uart_hwin(uport, DM270_UART_RFCR) | + (DM270_UART_RFCR_RESET | DM270_UART_RFCR_CLEAR)); +} + +static inline void +dm270_uart_disable_breaks(struct uart_port *uport) +{ + dm270_uart_hwout(uport, DM270_UART_LCR, + dm270_uart_hwin(uport, DM270_UART_LCR) & ~DM270_UART_LCR_BOC); +} + +static inline void +dm270_uart_enable_breaks(struct uart_port *uport) +{ + dm270_uart_hwout(uport, DM270_UART_LCR, + dm270_uart_hwin(uport, DM270_UART_LCR) | DM270_UART_LCR_BOC); +} + +static inline void +dm270_uart_set_rate(struct uart_port *uport, unsigned int rate) +{ + dm270_uart_hwout(uport, DM270_UART_BRSR, DM270_UART_BRSR_VAL(rate)); +} + +static inline void +dm270_uart_set_mode(struct uart_port *uport, unsigned short mode) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr = (dm270_uport->msr & ~(DM270_UART_MSR_CLS | DM270_UART_MSR_SBLS | + DM270_UART_MSR_PSB | DM270_UART_MSR_PEB)) | mode; + dm270_uart_hwout(uport, DM270_UART_MSR, dm270_uport->msr); +} + +static inline void +dm270_uart_set_rx_trigger(struct uart_port *uport, unsigned short val) +{ + dm270_uart_hwout(uport, DM270_UART_RFCR, (dm270_uart_hwin(uport, DM270_UART_RFCR) & + ~(DM270_UART_RFCR_RTL_MASK | DM270_UART_RFCR_RESET | + DM270_UART_RFCR_CLEAR)) | val); +} + +static inline void +dm270_uart_set_tx_trigger(struct uart_port *uport, unsigned short val) +{ + dm270_uart_hwout(uport, DM270_UART_TFCR, (dm270_uart_hwin(uport, DM270_UART_TFCR) & + ~(DM270_UART_TFCR_TTL_MASK | DM270_UART_TFCR_CLEAR)) | + val); +} + +static inline void +dm270_uart_char_out(struct uart_port *uport, u8 val) +{ + dm270_uart_hwout(uport, DM270_UART_DTRR, val); +} + +static inline unsigned char +dm270_uart_char_in(struct uart_port *uport, unsigned short *status) +{ + unsigned short dtrr; + + dtrr = dm270_uart_hwin(uport, DM270_UART_DTRR); + *status = (dtrr & 0xff00); + return ((unsigned char)(dtrr & 0x00ff)); +} + +static inline int +dm270_uart_error_condition(unsigned short status) +{ + return ((status ^ DM270_UART_DTRR_RVF) & + (DM270_UART_DTRR_RVF | DM270_UART_DTRR_BF | DM270_UART_DTRR_FE | + DM270_UART_DTRR_ORF | DM270_UART_DTRR_PEF)); +} + +static inline int +dm270_uart_break_condition(unsigned short status) +{ + return (status & DM270_UART_DTRR_BF); +} + +static inline int +dm270_uart_parity_error(unsigned short status) +{ + return (status & DM270_UART_DTRR_PEF); +} + +static inline int +dm270_uart_framing_error(unsigned short status) +{ + return (status & DM270_UART_DTRR_FE); +} + +static inline int +dm270_uart_overrun_error(unsigned short status) +{ + return (status & DM270_UART_DTRR_ORF); +} + +static inline int +dm270_uart_received_word_invalid(unsigned short status) +{ + return (status & DM270_UART_DTRR_RVF); +} + +static inline unsigned short +dm270_uart_tx_fifo_empty(struct uart_port *uport) +{ + return (dm270_uart_hwin(uport, DM270_UART_SR) & DM270_UART_SR_TREF); +} + +static inline unsigned short +dm270_uart_room_in_tx_fifo(struct uart_port *uport) +{ + return ((dm270_uart_hwin(uport, DM270_UART_TFCR) & DM270_UART_TFCR_TWC_MASK) < DM270_UART_TXFIFO_BYTESIZE); +} + +static inline unsigned short +dm270_uart_rx_fifo_has_content(struct uart_port *uport) +{ + return (dm270_uart_hwin(uport, DM270_UART_SR) & DM270_UART_SR_RFNEF); +} + +static inline void +dm270_uart_save_registers(struct uart_port *uport) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + dm270_uport->msr = dm270_uart_hwin(uport, DM270_UART_MSR); +} + +/** + ** + ** interrupt functions + ** + **/ + +static inline void +dm270_uart_rx_chars(struct uart_port *uport, struct pt_regs *ptregs) +{ + struct tty_struct *tty = uport->info->tty; + unsigned short status; + unsigned char ch; + int max_count = 256; + + do { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + + ch = dm270_uart_char_in(uport, &status); + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + uport->icount.rx++; + + if (dm270_uart_error_condition(status)) { + /* For statistics only */ + if (dm270_uart_break_condition(status)) { + status &= ~(DM270_UART_DTRR_FE | DM270_UART_DTRR_PEF); + uport->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(uport)) + goto ignore_char; + } else if (dm270_uart_parity_error(status)) { + uport->icount.parity++; + } else if (dm270_uart_framing_error(status)) { + uport->icount.frame++; + } + if (dm270_uart_overrun_error(status)) + uport->icount.overrun++; + + /* Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + status &= uport->read_status_mask; +#if 0 +#ifdef CONFIG_SERIAL_DM270_CONSOLE + if (uport->line == uport->cons->index) { + /* Recover the break flag from console xmit */ + status |= dm270_uport->dtrr_break_flag; + dm270_uport->dtrr_break_flag = 0; + } +#endif +#endif + if (dm270_uart_break_condition(status)) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + } else if (dm270_uart_parity_error(status)) { + *tty->flip.flag_buf_ptr = TTY_PARITY; + } else if (dm270_uart_framing_error(status)) { + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + } + if (uart_handle_sysrq_char(uport, ch, ptregs)) + goto ignore_char; + if ((status & uport->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if (dm270_uart_overrun_error(status) && + (tty->flip.count < TTY_FLIPBUF_SIZE)) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + ignore_char: + } while (dm270_uart_rx_fifo_has_content(uport) && (max_count-- > 0)); + + tty_flip_buffer_push(tty); +} + +static inline void +dm270_uart_tx_chars(struct uart_port *uport) +{ + struct circ_buf *xmit = &uport->info->xmit; + int count; + + if (uport->x_char) { + dm270_uart_char_out(uport, uport->x_char); + uport->icount.tx++; + uport->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(uport)) { + dm270_uart_stop_tx(uport, 0); + return; + } + + /* Send while we still have data & room in the fifo */ + count = uport->fifosize; + do { + dm270_uart_char_out(uport, xmit->buf[xmit->tail++]); + xmit->tail &= (UART_XMIT_SIZE - 1); + uport->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(uport); + + if (uart_circ_empty(xmit)) + dm270_uart_stop_tx(uport, 0); +} + +static irqreturn_t +dm270_uart_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +{ + struct uart_port *uport = dev_id; + unsigned short status; + int pass_counter = 0; + + status = dm270_uart_hwin(uport, DM270_UART_SR); + while (status & (DM270_UART_SR_RFNEF | DM270_UART_SR_TFEF)) { + if (status & DM270_UART_SR_RFNEF) + dm270_uart_rx_chars(uport, ptregs); + + if (status & DM270_UART_SR_TFEF) + dm270_uart_tx_chars(uport); + + if (pass_counter++ > UART_ISR_PASS_LIMIT) { + break; + } + + status = dm270_uart_hwin(uport, DM270_UART_SR); + } + + return IRQ_HANDLED; +} + +/** + ** + ** struct uart_ops functions + ** + **/ + +static unsigned int +dm270_uart_tx_empty(struct uart_port *uport) +{ + return dm270_uart_tx_fifo_empty(uport); +} + +static void +dm270_uart_set_mctrl(struct uart_port *uport, unsigned int mctrl) +{ + return; +} + +static unsigned int +dm270_uart_get_mctrl(struct uart_port *uport) +{ + return 0; +} + +static void +dm270_uart_stop_tx(struct uart_port *uport, unsigned int tty_stop) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + if (dm270_uport->msr & DM270_UART_MSR_TFTIE) { + dm270_uart_disable_tx_int(uport); + } +} + +static void +dm270_uart_start_tx(struct uart_port *uport, unsigned int tty_start) +{ + struct dm270_uart_port *dm270_uport = (struct dm270_uart_port *)uport; + + if (!(dm270_uport->msr & DM270_UART_MSR_TFTIE)) { + dm270_uart_enable_tx_int(uport); + } +} + +static void dm270_uart_send_xchar(struct uart_port *uport, char ch) +{ + uport->x_char = ch; + if (ch) { + dm270_uart_enable_tx_int(uport); + } +} + +static void +dm270_uart_stop_rx(struct uart_port *uport) +{ + dm270_uart_disable_rx_int(uport); +} + +static void dm270_uart_enable_ms(struct uart_port *uport) +{ + return; +} + +static void +dm270_uart_break_ctl(struct uart_port *uport, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&uport->lock, flags); + + if (break_state == -1) + dm270_uart_enable_breaks(uport); + else + dm270_uart_disable_breaks(uport); + + spin_unlock_irqrestore(&uport->lock, flags); +} + +static int +dm270_uart_startup(struct uart_port *uport) +{ + unsigned short junk; + int retval; + + dm270_uart_hwreset(uport); + dm270_uart_save_registers(uport); + dm270_uart_disable_ints(uport, &junk); + dm270_uart_clear_fifos(uport); + dm270_uart_disable_breaks(uport); + dm270_uart_set_rate(uport, UART_DEFAULT_BAUD); + dm270_uart_set_tx_trigger(uport, DM270_UART_TFCR_TRG_1); + dm270_uart_set_rx_trigger(uport, DM270_UART_RFCR_TRG_16); + + /* Allocate the IRQ */ + retval = request_irq(uport->irq, dm270_uart_interrupt, SA_INTERRUPT, + UART_TYPE, uport); + if (retval) + return retval; + + /* Finally, enable interrupts */ + dm270_uart_enable_rx_int(uport); + return 0; +} + +static void +dm270_uart_shutdown(struct uart_port *uport) +{ + unsigned short junk; + + /* Free the IRQ */ + free_irq(uport->irq, uport); + + dm270_uart_disable_ints(uport, &junk); /* disable all intrs */ + dm270_uart_disable_breaks(uport); /* disable break condition */ + dm270_uart_clear_fifos(uport); /* reset FIFO's */ +} + +static void +dm270_uart_set_termios(struct uart_port *uport, struct termios *termios, struct termios *old) +{ + unsigned short cval; + unsigned long flags; + unsigned int baud; + + /* Byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS7: + cval = DM270_UART_MSR_7_DBITS; + break; + case CS8: + default: + cval = DM270_UART_MSR_8_DBITS; + break; + } + + if (termios->c_cflag & CSTOPB) { + cval |= DM270_UART_MSR_2_SBITS; + } else { + cval |= DM270_UART_MSR_1_SBITS; + } + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) { + cval |= DM270_UART_MSR_ODD_PARITY; + } else { + cval |= DM270_UART_MSR_EVEN_PARITY; + } + } else if (termios->c_cflag & PARODD) { + cval |= DM270_UART_MSR_ODD_PARITY; + } else { + cval |= DM270_UART_MSR_NO_PARITY; + } + + baud = uart_get_baud_rate(uport, termios, old, 0, uport->uartclk/16); + if (baud == 0) { + baud = 9600; + } + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&uport->lock, flags); + + /* Update the per-port timeout */ + uart_update_timeout(uport, termios->c_cflag, baud); + + uport->read_status_mask = (DM270_UART_DTRR_ORF | DM270_UART_DTRR_RVF); + if (termios->c_iflag & INPCK) + uport->read_status_mask |= (DM270_UART_DTRR_PEF | DM270_UART_DTRR_FE); + if (termios->c_iflag & (BRKINT | PARMRK)) + uport->read_status_mask |= DM270_UART_DTRR_BF; + + /* Characters to ignore */ + uport->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= (DM270_UART_DTRR_PEF | DM270_UART_DTRR_FE); + if (termios->c_iflag & IGNBRK) { + uport->ignore_status_mask |= DM270_UART_DTRR_BF; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= DM270_UART_DTRR_ORF; + } + + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + uport->ignore_status_mask |= DM270_UART_DTRR_RVF; + + dm270_uart_set_rate(uport, baud); + dm270_uart_set_mode(uport, cval); + + /* + * We should always set the receive FIFO trigger to the lowest value + * because we don't poll. + */ + dm270_uart_set_rx_trigger(uport, DM270_UART_RFCR_TRG_1); + + spin_unlock_irqrestore(&uport->lock, flags); +} + +static void +dm270_uart_pm(struct uart_port *uport, unsigned int state, unsigned int oldstate) +{ + return; +} + +static int +dm270_uart_set_wake(struct uart_port *uport, unsigned int state) +{ + return 0; +} + +static const char * +dm270_uart_type(struct uart_port *uport) +{ + return UART_TYPE; +} + + +static void +dm270_uart_release_port(struct uart_port *uport) +{ + return; +} + +static int +dm270_uart_request_port(struct uart_port *uport) +{ + return 0; +} + +static void +dm270_uart_config_port(struct uart_port *uport, int config) +{ + return; +} + +static int dm270_uart_verify_port(struct uart_port *uport, struct serial_struct *serial) +{ + if (serial->port != uport->iobase || serial->irq != uport->irq || + serial->baud_base < 9600 || serial->xmit_fifo_size <= 0 || + serial->io_type != uport->iotype || serial->type != uport->type || + serial->line != uport->line) + return -EINVAL; + return 0; +} + +static int dm270_uart_ioctl(struct uart_port *uport, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +static struct uart_ops dm270_uart_ops = { + tx_empty: dm270_uart_tx_empty, + set_mctrl: dm270_uart_set_mctrl, + get_mctrl: dm270_uart_get_mctrl, + stop_tx: dm270_uart_stop_tx, + start_tx: dm270_uart_start_tx, + send_xchar: dm270_uart_send_xchar, + stop_rx: dm270_uart_stop_rx, + enable_ms: dm270_uart_enable_ms, + break_ctl: dm270_uart_break_ctl, + startup: dm270_uart_startup, + shutdown: dm270_uart_shutdown, + set_termios: dm270_uart_set_termios, + pm: dm270_uart_pm, + set_wake: dm270_uart_set_wake, + type: dm270_uart_type, + release_port: dm270_uart_release_port, + request_port: dm270_uart_request_port, + config_port: dm270_uart_config_port, + verify_port: dm270_uart_verify_port, + ioctl: dm270_uart_ioctl, +}; + +static struct uart_port dm270_uart_ports[UART_NR] = { + { + iobase: DM270_UART0_BASE, + irq: DM270_INTERRUPT_UART0, + uartclk: CONFIG_ARM_CLK, + fifosize: DM270_UART_TXFIFO_BYTESIZE, + iotype: UPIO_PORT, + type: PORT_DM270, + ops: &dm270_uart_ops, + line: 0, + }, + { + iobase: DM270_UART1_BASE, + irq: DM270_INTERRUPT_UART1, + uartclk: CONFIG_ARM_CLK, + fifosize: DM270_UART_TXFIFO_BYTESIZE, + iotype: UPIO_PORT, + type: PORT_DM270, + ops: &dm270_uart_ops, + line: 1, + } +}; + +#ifdef CONFIG_SERIAL_DM270_CONSOLE +/************** console driver *****************/ + +/* + * This block is enabled when the user has used `make xconfig` + * to enable kernel printk() to come out the serial port. + * The register_console(&dm270_console) call below is what hooks in + * our serial output routine here with the kernel's printk output. + */ + +/* + * Wait for transmitter & holding register to empty + */ + +static inline void +dm270_console_wait_for_xmitr(struct uart_port *uport) +{ + int tmp; + + for (tmp = 1000000 ; tmp > 0 ; tmp--) + if (dm270_uart_room_in_tx_fifo(uport)) + break; +} + +/* + * 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 +dm270_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *uport = &dm270_uart_ports[co->index]; + unsigned short msr; + unsigned int ii; + + /* First save the MSR then disable the interrupts */ + dm270_uart_disable_ints(uport, &msr); + + /* Now, do each character */ + for (ii = 0; ii < count; ii++, s++) { + dm270_console_wait_for_xmitr(uport); + /* + * Send the character out. + * If a LF, also do CR... + */ + dm270_uart_char_out(uport, *s); + if (*s == 10) { + /* LF? add CR */ + dm270_console_wait_for_xmitr(uport); + dm270_uart_char_out(uport, 13); + } + } + + /* + * Finally, wait for transmitter & holding register to empty + * and restore the MSR + */ + dm270_console_wait_for_xmitr(uport); + dm270_uart_restore_ints(uport, msr); +} + +/* + * Setup initial baud/bits/parity/flow control + */ + +static int __init +dm270_console_setup(struct console *co, char *options) +{ + struct uart_port *uport; + int baud = CONSOLE_DEFAULT_BAUD; + int bits = CONSOLE_DEFAULT_BITS; + int parity = CONSOLE_DEFAULT_PARITY; + int flow = CONSOLE_DEFAULT_FLOW; + unsigned short junk; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + uport = uart_get_console(dm270_uart_ports, UART_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + dm270_uart_hwreset(uport); + dm270_uart_save_registers(uport); + dm270_uart_disable_ints(uport, &junk); + dm270_uart_clear_fifos(uport); + dm270_uart_disable_breaks(uport); + dm270_uart_set_tx_trigger(uport, DM270_UART_TFCR_TRG_1); + + return uart_set_options(uport, co, baud, parity, bits, flow); +} + +extern struct uart_driver dm270_uart_driver; + +static struct console dm270_console = { + name: "ttyS", + write: dm270_console_write, + device: uart_console_device, + setup: dm270_console_setup, + flags: CON_PRINTBUFFER, + index: -1, + data: &dm270_uart_driver, +}; + +static int __init +dm270_console_init(void) +{ + register_console(&dm270_console); + return 0; +} + +console_initcall(dm270_console_init); + +#endif /* CONFIG_SERIAL_DM270_CONSOLE */ + +static struct uart_driver dm270_uart_driver = { + owner: THIS_MODULE, + driver_name: UART_DRIVER_NAME, + devfs_name: "tts/", + dev_name: "ttyS", + major: TTY_MAJOR, + minor: 64, + nr: UART_NR, +#ifdef CONFIG_SERIAL_DM270_CONSOLE + cons: &dm270_console, +#endif +}; + +static int __init +dm270_uart_init(void) +{ + int retval; + int ii; + + retval = uart_register_driver(&dm270_uart_driver); + if (retval) + return retval; + + for (ii = 0; ii < UART_NR; ii++) { + retval = uart_add_one_port(&dm270_uart_driver, &dm270_uart_ports[ii]); + if (retval) + return retval; + } + + return 0; +} + +static void __exit +dm270_uart_exit(void) +{ + int ii; + + for (ii = 0; ii < UART_NR; ii++) { + uart_remove_one_port(&dm270_uart_driver, &dm270_uart_ports[ii]); + } + + uart_unregister_driver(&dm270_uart_driver); +} + +module_init(dm270_uart_init); +module_exit(dm270_uart_exit); + +MODULE_AUTHOR("Chee Tim Loh "); +MODULE_DESCRIPTION("DM270 UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c new file mode 100644 index 00000000..40eba6f8 --- /dev/null +++ b/drivers/serial/serial_ks8695.c @@ -0,0 +1,569 @@ +/* + * linux/drivers/char/serial_ks8695.c + * + * Driver for KS8695 serial port + * + * Based on drivers/serial/serial_ks8695uart.c, by Kam Lee. + * + * Copyright 2002 Micrel Inc. + * (C) Copyrght 2006 Greg Ungerer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KS8695_UART_NR 1 + +#ifdef CONFIG_SERIAL_KS8695_COM +#define KS8695_SERIAL_MAJOR 4 +#define KS8695_SERIAL_MINOR 64 +#define KS8695_SERIAL_DEV_NAME "ttyS" +#else +#define KS8695_SERIAL_MAJOR 204 +#define KS8695_SERIAL_MINOR 16 +#define KS8695_SERIAL_DEV_NAME "ttyAM" +#endif + +/* + * Access macros for the KS8695 UART + */ +#define UART_GET_INT_STATUS(p) (*(volatile unsigned int *)((p)->membase + KS8695_INT_STATUS)) +#define UART_CLR_INT_STATUS(p, c) (*(unsigned int *)((p)->membase + KS8695_INT_STATUS) = (c)) +#define UART_GET_CHAR(p) ((*(volatile unsigned int *)((p)->membase + KS8695_UART_RX_BUFFER)) & 0xFF) +#define UART_PUT_CHAR(p, c) (*(unsigned int *)((p)->membase + KS8695_UART_TX_HOLDING) = (c)) +#define UART_GET_IER(p) (*(volatile unsigned int *)((p)->membase + KS8695_INT_ENABLE)) +#define UART_PUT_IER(p, c) (*(unsigned int *)((p)->membase + KS8695_INT_ENABLE) = (c)) +#define UART_GET_FCR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_FIFO_CTRL)) +#define UART_PUT_FCR(p, c) (*(unsigned int *)((p)->membase + KS8695_UART_FIFO_CTRL) = (c)) +#define UART_GET_MSR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_MODEM_STATUS)) +#define UART_GET_LSR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_LINE_STATUS)) +#define UART_GET_LCR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_LINE_CTRL)) +#define UART_PUT_LCR(p, c) (*(unsigned int *)((p)->membase + KS8695_UART_LINE_CTRL) = (c)) +#define UART_GET_MCR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_MODEM_CTRL)) +#define UART_PUT_MCR(p, c) (*(unsigned int *)((p)->membase + KS8695_UART_MODEM_CTRL) = (c)) +#define UART_GET_BRDR(p) (*(volatile unsigned int *)((p)->membase + KS8695_UART_DIVISOR)) +#define UART_PUT_BRDR(p, c) (*(unsigned int *)((p)->membase + KS8695_UART_DIVISOR) = (c)) +#define UART_RX_DATA(s) (((s) & KS8695_UART_LINES_RXFE) != 0) +#define UART_TX_READY(s) (((s) & KS8695_UART_LINES_TXFE) != 0) + +#define UART_DUMMY_LSR_RX 0x100 + +static void ks8695uart_stop_tx(struct uart_port *port) +{ + unsigned int ier; + + ier = UART_GET_IER(port); + if (ier & KS8695_INT_ENABLE_TX) + disable_irq(8); +} + +static void ks8695uart_start_tx(struct uart_port *port) +{ + unsigned int ier; + + ier = UART_GET_IER(port); + if ((ier & KS8695_INT_ENABLE_TX ) == 0) + enable_irq(8); +} + +static void ks8695uart_stop_rx(struct uart_port *port) +{ + unsigned int ier; + + ier = UART_GET_IER(port); + ier &= ~KS8695_INT_ENABLE_RX; + UART_PUT_IER(port, ier); +} + +static void ks8695uart_enable_ms(struct uart_port *port) +{ + UART_PUT_IER(port, UART_GET_IER(port) | KS8695_INT_ENABLE_MODEM); +} + +static irqreturn_t ks8695uart_tx_chars(int irq, void *data) +{ + struct uart_port *port = data; + struct circ_buf *xmit = &port->info->xmit; + int i; + + if (port->x_char) { + UART_CLR_INT_STATUS(port, KS8695_INTMASK_UART_TX); + UART_PUT_CHAR(port, (unsigned int) port->x_char); + port->icount.tx++; + port->x_char = 0; + return IRQ_HANDLED; + } + + for (i = 0; (i < 16); i++) { + if (xmit->head == xmit->tail) + break; + UART_CLR_INT_STATUS(port, KS8695_INTMASK_UART_TX); + UART_PUT_CHAR(port, (unsigned int) (xmit->buf[xmit->tail])); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (xmit->head == xmit->tail) + disable_irq(irq); + + return IRQ_HANDLED; +} + +static irqreturn_t ks8695uart_rx_chars(int irq, void *data) +{ + struct uart_port *port = data; + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, lsr, max_count = 256; + char flag; + + status = UART_GET_LSR(port); + while (UART_RX_DATA(status) && max_count--) { + + ch = UART_GET_CHAR(port); + flag = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX; + if (lsr & KS8695_UART_LINES_ANY) { + if (lsr & KS8695_UART_LINES_BE) { + lsr &= ~(KS8695_UART_LINES_FE | KS8695_UART_LINES_FE); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & KS8695_UART_LINES_PE) + port->icount.parity++; + else if (lsr & KS8695_UART_LINES_FE) + port->icount.frame++; + if (lsr & KS8695_UART_LINES_OE) + port->icount.overrun++; + + lsr &= port->read_status_mask; + + if (lsr & KS8695_UART_LINES_BE) + flag = TTY_BREAK; + else if (lsr & KS8695_UART_LINES_PE) + flag = TTY_PARITY; + else if (lsr & KS8695_UART_LINES_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, KS8695_UART_LINES_OE, ch, flag); + +ignore_char: + status = UART_GET_LSR(port); + } + + tty_flip_buffer_push(tty); + return IRQ_HANDLED; +} + + +static irqreturn_t ks8695uart_modem(int irq, void *data) +{ + struct uart_port *port = data; + unsigned int status, delta; + + /* clear modem interrupt by reading MSR */ + status = UART_GET_MSR(port); + delta = status & 0x0B; + + if (!delta) + return IRQ_NONE; + + if (delta & KS8695_UART_MODEM_DDCD) + uart_handle_dcd_change(port, status & KS8695_UART_MODEM_DDCD); + if (delta & KS8695_UART_MODEM_DDSR) + port->icount.dsr++; + if (delta & KS8695_UART_MODEM_DCTS) + uart_handle_cts_change(port, status & KS8695_UART_MODEM_DCTS); + wake_up_interruptible(&port->info->delta_msr_wait); + + return IRQ_HANDLED; +} + +static unsigned int ks8695uart_tx_empty(struct uart_port *port) +{ + unsigned int status; + + status = UART_GET_LSR(port); + return UART_TX_READY(status) ? TIOCSER_TEMT : 0; +} + +static unsigned int ks8695uart_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_MSR(port); + if (status & KS8695_UART_MODEM_DCD) + result |= TIOCM_CAR; + if (status & KS8695_UART_MODEM_DSR) + result |= TIOCM_DSR; + if (status & KS8695_UART_MODEM_CTS) + result |= TIOCM_CTS; + + return result; +} + +static void ks8695uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int mcr; + + mcr = UART_GET_MCR(port); + if (mctrl & TIOCM_RTS) + mcr |= KS8695_UART_MODEMC_RTS; + else + mcr &= ~KS8695_UART_MODEMC_RTS; + + if (mctrl & TIOCM_DTR) + mcr |= KS8695_UART_MODEMC_DTR; + else + mcr &= ~KS8695_UART_MODEMC_DTR; + + UART_PUT_MCR(port, mcr); +} + +static void ks8695uart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned int lcr; + + lcr = UART_GET_LCR(port); + if (break_state == -1) + lcr |= KS8695_UART_LINEC_BRK; + else + lcr &= ~KS8695_UART_LINEC_BRK; + UART_PUT_LCR(port, lcr); +} + +static int ks8695uart_startup(struct uart_port *port) +{ + int retval; + + retval = request_irq(KS8695_INT_UART_TX, ks8695uart_tx_chars, SA_SHIRQ | SA_INTERRUPT, "KS8695 uart(TX)", port); + if (retval) + return retval; + + retval = request_irq(KS8695_INT_UART_RX, ks8695uart_rx_chars, SA_SHIRQ | SA_INTERRUPT, "KS8695 uart(RX)", port); + if (retval) + return retval; + + retval = request_irq(KS8695_INT_UART_LINE_ERR, ks8695uart_rx_chars, SA_SHIRQ | SA_INTERRUPT, "KS8695 uart(error)", port); + if (retval) + return retval; + + retval = request_irq(KS8695_INT_UART_MODEMS, ks8695uart_modem, SA_SHIRQ | SA_INTERRUPT, "KS8695 uart(modem)", port); + if (retval) + return retval; + + return 0; +} + +static void ks8695uart_shutdown(struct uart_port *port) +{ + /* disable break condition and fifos */ + UART_PUT_LCR(port, UART_GET_LCR(port) & ~KS8695_UART_LINEC_BRK); + UART_PUT_FCR(port, UART_GET_FCR(port) & ~KS8695_UART_FIFO_FEN); + + free_irq(KS8695_INT_UART_RX, port); + free_irq(KS8695_INT_UART_TX, port); + free_irq(KS8695_INT_UART_LINE_ERR, port); + free_irq(KS8695_INT_UART_MODEMS, port); +} + +static void ks8695uart_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) +{ + unsigned int baud, lcr, fcr = 0; + unsigned long flags; + + /* byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS5: lcr = KS8695_UART_LINEC_WLEN5; break; + case CS6: lcr = KS8695_UART_LINEC_WLEN6; break; + case CS7: lcr = KS8695_UART_LINEC_WLEN7; break; + default: lcr = KS8695_UART_LINEC_WLEN8; break; // CS8 + } + + if (termios->c_cflag & CSTOPB) + lcr |= KS8695_UART_LINEC_STP2; + if (termios->c_cflag & PARENB) { + lcr |= KS8695_UART_LINEC_PEN; + if (!(termios->c_cflag & PARODD)) + lcr |= KS8695_UART_LINEC_EPS; + } + + if (port->fifosize > 1) + fcr = KS8695_UART_FIFO_TRIG04 | KS8695_UART_FIFO_TXRST | KS8695_UART_FIFO_RXRST | KS8695_UART_FIFO_FEN; + + port->read_status_mask = KS8695_UART_LINES_OE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= (KS8695_UART_LINES_FE | KS8695_UART_LINES_PE); + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= KS8695_UART_LINES_BE; + + /* Characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= (KS8695_UART_LINES_FE | KS8695_UART_LINES_PE); + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= KS8695_UART_LINES_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 |= KS8695_UART_LINES_OE; + } + + /* Ignore all characters if CREAD is not set. */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_LSR_RX; + + baud = uart_get_baud_rate(port, termios, old, 50, 230400); + + /* first, disable everything */ + local_irq_save(flags); + + if ((port->flags & ASYNC_HARDPPS_CD) || + (termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL)) + ks8695uart_enable_ms(port); + + UART_PUT_BRDR(port, port->uartclk / baud); + UART_PUT_LCR(port, lcr); + UART_PUT_FCR(port, fcr); + + local_irq_restore(flags); +} + +static const char *ks8695uart_type(struct uart_port *port) +{ + return port->type == PORT_KS8695 ? "KS8695" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void ks8695uart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 0x24); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int ks8695uart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, 0x24, "KS8695 UART") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void ks8695uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_KS8695; + ks8695uart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_KS8695)) + return -EINVAL; + if ((ser->irq < 0) || (ser->irq >= NR_IRQS)) + return -EINVAL; + if (ser->baud_base < 9600) + return -EINVAL; + return 0; +} + +static struct uart_ops ks8695uart_ops = { + .tx_empty = ks8695uart_tx_empty, + .set_mctrl = ks8695uart_set_mctrl, + .get_mctrl = ks8695uart_get_mctrl, + .stop_tx = ks8695uart_stop_tx, + .start_tx = ks8695uart_start_tx, + .stop_rx = ks8695uart_stop_rx, + .enable_ms = ks8695uart_enable_ms, + .break_ctl = ks8695uart_break_ctl, + .startup = ks8695uart_startup, + .shutdown = ks8695uart_shutdown, + .set_termios = ks8695uart_set_termios, + .type = ks8695uart_type, + .release_port = ks8695uart_release_port, + .request_port = ks8695uart_request_port, + .config_port = ks8695uart_config_port, + .verify_port = ks8695uart_verify_port, +}; + +static struct uart_port ks8695uart_ports[KS8695_UART_NR] = { + { + .line = 0, + .membase = (void *) KS8695_IO_VIRT, + .mapbase = KS8695_IO_BASE + KS8695_UART_RX_BUFFER, + .iotype = SERIAL_IO_MEM, + .irq = KS8695_INT_UART_RX, + .uartclk = 25000000, + .fifosize = 16, + .ops = &ks8695uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + } +}; + +#ifdef CONFIG_SERIAL_KS8695_CONSOLE + +/* + * Force a single char out the serial. It must go out, poll the ready + * register until we can send it, and make sure it is sent. + */ +static void ks8695uart_console_putc(struct console *co, const char c) +{ + struct uart_port *port = ks8695uart_ports + co->index; + + while (!UART_TX_READY(UART_GET_LSR(port))) + ; + + UART_PUT_CHAR(port, (unsigned int) c); + + while (!UART_TX_READY(UART_GET_LSR(port))) + ; +} + +static void ks8695uart_console_write(struct console *co, const char *s, unsigned int count) +{ + int i; + + for (i = 0; i < count; i++, s++) { + ks8695uart_console_putc(co, *s); + if (*s == '\n') + ks8695uart_console_putc(co, '\r'); + } +} + +static int __init ks8695uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + port = uart_get_console(ks8695uart_ports, KS8695_UART_NR, co); + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver ks8695uart_reg; +static struct console ks8695uart_console = { + .name = KS8695_SERIAL_DEV_NAME, + .write = ks8695uart_console_write, + .device = uart_console_device, + .setup = ks8695uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ks8695uart_reg, +}; + +static int __init ks8695uart_console_init(void) +{ + register_console(&ks8695uart_console); + return 0; +} + +console_initcall(ks8695uart_console_init); + +#define KS8695UART_CONSOLE &ks8695uart_console +#else +#define KS8695UART_CONSOLE NULL +#endif + +static struct uart_driver ks8695uart_reg = { + .owner = THIS_MODULE, + .driver_name = "serial_ks8695", + .dev_name = KS8695_SERIAL_DEV_NAME, + .major = KS8695_SERIAL_MAJOR, + .minor = KS8695_SERIAL_MINOR, + .nr = KS8695_UART_NR, + .cons = KS8695UART_CONSOLE, +}; + +static int __init ks8695uart_init(void) +{ + int i, rc; + + rc = uart_register_driver(&ks8695uart_reg); + if (rc == 0) { + for (i = 0; (i < KS8695_UART_NR); i++) + uart_add_one_port(&ks8695uart_reg, &ks8695uart_ports[i]); + } + + return rc; +} + +static void __exit ks8695uart_exit(void) +{ + int i; + + for (i = 0; (i < KS8695_UART_NR); i++) + uart_remove_one_port(&ks8695uart_reg, &ks8695uart_ports[i]); + uart_unregister_driver(&ks8695uart_reg); +} + +module_init(ks8695uart_init); +module_exit(ks8695uart_exit); + +MODULE_AUTHOR("Micrel Semiconductor"); +MODULE_DESCRIPTION("KS8695 serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_s3c24a0.c b/drivers/serial/serial_s3c24a0.c new file mode 100644 index 00000000..bf43a1be --- /dev/null +++ b/drivers/serial/serial_s3c24a0.c @@ -0,0 +1,595 @@ +/* + * drivser/serial/serial_s3c24a0.c + * + * device for S3C24A0 + * + * $Id: serial_s3c24a0.c,v 1.3 2006/12/12 13:38:51 gerg Exp $ + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CONFIG_USE_ERR_IRQ 0 + +#define __DRIVER_NAME "Samsung S3C24A0 Internal UART" + + +#ifdef CONFIG_BOARD_S3C24A0_SMDK +#define UART_NR 1 +#else +#define UART_NR 2 +#endif + +#define UART_ULCON(port) __REG((port)->iobase + oULCON) +#define UART_UCON(port) __REG((port)->iobase + oUCON) +#define UART_UFCON(port) __REG((port)->iobase + oUFCON) +#define UART_UTRSTAT(port) __REG((port)->iobase + oUTRSTAT) +#define UART_UERSTAT(port) __REG((port)->iobase + oUERSTAT) +#define UART_UTXH(port) __REG((port)->iobase + oUTXH) +#define UART_URXH(port) __REG((port)->iobase + oURXH) +#define UART_UBRDIV(port) __REG((port)->iobase + oUBRDIV) + +#define ERR_IRQ(port) ((port)->irq + 2) +#define TX_IRQ(port) ((port)->irq + 1) +#define RX_IRQ(port) ((port)->irq) + +#define INT_DISABLE(port) disable_irq(port); +#define INT_ENABLE(port) enable_irq(port); +/* + * Internal helper function + */ +static void __xmit_char(struct uart_port *port, const char ch) +{ + while (!(UART_UTRSTAT(port) & UTRSTAT_TX_EMP)); + UART_UTXH(port) = ch; + if (ch == '\n') { + while (!(UART_UTRSTAT(port) & UTRSTAT_TX_EMP)); + UART_UTXH(port) = '\r'; + } +} + +static void __xmit_string(struct uart_port *port, const char *p, int len) +{ + while( len-- > 0) { + __xmit_char( port, *p++); + } +} + + + +static void elfinuart_stop_tx(struct uart_port *port) +{ +} + +static void elfinuart_start_tx(struct uart_port *port) +{ + struct uart_info *info = port->info; + struct circ_buf *xmit = &port->info->xmit; + + int count; + + if (port->x_char) { + __xmit_char(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty( xmit) || uart_tx_stopped( port)) { + elfinuart_stop_tx(port); + return; + } + + count = port->fifosize >> 1; + do { + __xmit_char( port, xmit->buf[xmit->tail]); + info->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)) + elfinuart_stop_tx( port); +} + +static void elfinuart_stop_rx(struct uart_port *port) +{ +} + +static void elfinuart_enable_ms(struct uart_port *port) +{ +} + +static void elfinuart_rx_char(struct uart_port *port) +{ + unsigned int status, ch, max_count = 256; + struct tty_struct *tty = port->info->tty; + + status = UART_UTRSTAT(port); + while ((status & UTRSTAT_RX_RDY) && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.work.func((void *) tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + ch = UART_URXH(port); + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + /* No error handling just yet. + * On the MX1 these are seperate + * IRQs, so we need to deal with + * the sanity of 5 IRQs for one + * serial port before we deal + * with the error path properly. + */ + status = UART_UTRSTAT(port); + } + tty_flip_buffer_push(tty); +} + +static u_int elfinuart_tx_empty(struct uart_port *port) +{ + return (UART_UTRSTAT(port) & UTRSTAT_TR_EMP ? 0 : TIOCSER_TEMT); +} + +static u_int elfinuart_get_mctrl(struct uart_port *port) +{ + return (TIOCM_CTS | TIOCM_DSR | TIOCM_CAR); +} + +static void elfinuart_set_mctrl(struct uart_port *port, u_int mctrl) +{ +} + +static void elfinuart_break_ctl(struct uart_port *port, int break_state) +{ + u_int ucon; + + ucon = UART_UCON(port); + + if (break_state == -1) + ucon |= UCON_BRK_SIG; + else + ucon &= ~UCON_BRK_SIG; + + UART_UCON(port) = ucon; +} + +static irqreturn_t elfinuart_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + elfinuart_rx_char(port); + + return IRQ_HANDLED; +} + +static irqreturn_t elfinuart_tx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + elfinuart_start_tx(port); + return IRQ_HANDLED; +} + +#ifdef CONFIG_USE_ERR_IRQ +static irqreturn_t elfinuart_err_int(int irq, void *dev_id, + struct pt_regs *reg) +{ + struct uart_port *port = dev_id; + struct uart_info *info = port->info; + struct tty_struct *tty = info->tty; + unsigned char err = UART_UERSTAT(port) & UERSTAT_ERR_MASK; + unsigned int ch, flg = TTY_NORMAL; + + ch = UART_URXH(port); + if (!err) + return IRQ_HANDLED; + + if (err & UERSTAT_OVERRUN) + port->icount.overrun++; + + err &= port->read_status_mask; + + if (err & UERSTAT_OVERRUN) { + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = flg; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + ch = 0; + flg = TTY_OVERRUN; + } + } + + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + return IRQ_HANDLED; +} +#endif + +static struct irqaction __rx_irqaction[UART_NR] = { + { + name: "serial0_rx", + flags: SA_INTERRUPT, + handler: elfinuart_rx_int, + }, + { + name: "serial1_rx", + flags: SA_INTERRUPT, + handler: elfinuart_rx_int, + }, +}; + +static struct irqaction __tx_irqaction[UART_NR] = { + { + name: "serial0_tx", + flags: SA_INTERRUPT, + handler: elfinuart_tx_int, + }, + { + name: "serial1_tx", + flags: SA_INTERRUPT, + handler: elfinuart_tx_int, + }, +}; + +static struct irqaction __err_irqaction[UART_NR] = { + { + name: "serial0_err", + flags: SA_INTERRUPT, + handler: elfinuart_err_int, + }, + { + name: "serial1_err", + flags: SA_INTERRUPT, + handler: elfinuart_err_int, + }, +}; + +static int elfinuart_startup(struct uart_port *port) +{ + int ret; + u_int ucon; + + /* + * Allocate the IRQs for TX and RX + */ + __tx_irqaction[port->line].dev_id = (void *)port; + __rx_irqaction[port->line].dev_id = (void *)port; + __err_irqaction[port->line].dev_id = (void *)port; + + ret = setup_irq( RX_IRQ(port), &__rx_irqaction[port->line]); + if (ret) goto rx_failed; + +#if 0 + ret = setup_irq( TX_IRQ(port), &__tx_irqaction[port->line]); + if (ret) goto tx_failed; +#endif + +#ifdef CONFIG_USE_ERR_IRQ + ret = setup_irq( ERR_IRQ(port), &__err_irqaction[port->line]); + if (ret) goto err_failed; +#endif + + ucon = (UCON_TX_INT_LVL | UCON_RX_INT_LVL | + UCON_TX_INT | UCON_RX_INT | UCON_RX_TIMEOUT); + + + spin_lock_irq( &port->lock); + + UART_UCON(port) = ucon; + + spin_unlock_irq( &port->lock); + + return 0; + +#ifdef CONFIG_USE_ERR_IRQ +err_failed: + printk(KERN_ERR "%s: err failed\n", __FUNCTION__); + INT_DISABLE( ERR_IRQ(port)); +#endif +tx_failed: + printk(KERN_ERR "%s: tx failed\n", __FUNCTION__); + INT_DISABLE( TX_IRQ(port)); +rx_failed: + printk(KERN_ERR "%s: rx failed\n", __FUNCTION__); + INT_DISABLE( RX_IRQ(port)); + return ret; +} + +static void elfinuart_shutdown(struct uart_port *port) +{ +#ifdef CONFIG_USE_ERR_IRQ + INT_DISABLE( ERR_IRQ(port)); +#endif + INT_DISABLE( TX_IRQ(port)); + INT_DISABLE( RX_IRQ(port)); + + UART_UCON(port) = 0x0; +} + +#if 0 +static void elfinuart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) +{ + u_int ulcon, ufcon; + int flags; + + ufcon = UART_UFCON(port); + + switch (cflag & CSIZE) { + case CS5: + ulcon = ULCON_WL5; + break; + case CS6: + ulcon = ULCON_WL6; + break; + case CS7: + ulcon = ULCON_WL7; + break; + default: + ulcon = ULCON_WL8; + break; + } + + if (cflag & CSTOPB) + ulcon |= ULCON_STOP; + if (cflag & PARENB) { + if (!(cflag & PARODD)) + ulcon |= ULCON_PAR_EVEN; + } + + if (port->fifosize > 1) + ufcon |= UFCON_FIFO_EN; + + port->read_status_mask = UERSTAT_OVERRUN; + + port->ignore_status_mask = 0; + if (iflag & IGNBRK) { + if (iflag & IGNPAR) + port->ignore_status_mask |= UERSTAT_OVERRUN; + } + + quot -= 1; + + spin_lock_irqsave( &port->lock, flags ); + + UART_UFCON(port) = ufcon; + UART_ULCON(port) = ulcon; + UART_UBRDIV(port) = quot; + + spin_unlock_irqrestore(&port->lock, flags); +} + +#endif + +static void elfinuart_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) +{ + int quot; + + uart_update_timeout(port, termios->c_cflag, 115200); +#if 0 + quot = uart_get_divisor(port, 115200); + elfinuart_change_speed(port, termios->c_cflag, 0, quot); +#endif + +} +static void elfinuart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +{ +} + +static int elfinuart_set_wake(struct uart_port *port, unsigned int state) +{ + return 0; +} + + + + +static const char *elfinuart_type(struct uart_port *port) +{ + return __DRIVER_NAME; +} + +static void elfinuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_S3C24A0; +} + +static void elfinuart_release_port(struct uart_port *port) +{ +} + +static int elfinuart_request_port(struct uart_port *port) +{ + return 0; +} + +static int elfinuart_verify_port(struct uart_port *port, struct serial_struct *serial) +{ + return 0; +} + +static struct uart_ops elfin_pops = { + tx_empty : elfinuart_tx_empty, + set_mctrl : elfinuart_set_mctrl, + get_mctrl : elfinuart_get_mctrl, + stop_tx : elfinuart_stop_tx, + start_tx : elfinuart_start_tx, + stop_rx : elfinuart_stop_rx, + enable_ms : elfinuart_enable_ms, + break_ctl : elfinuart_break_ctl, + startup : elfinuart_startup, + shutdown : elfinuart_shutdown, + set_termios: elfinuart_set_termios, + pm: elfinuart_pm, + set_wake: elfinuart_set_wake, + type : elfinuart_type, + config_port : elfinuart_config_port, + release_port : elfinuart_release_port, + request_port : elfinuart_request_port, + verify_port: elfinuart_verify_port, +}; + +static struct uart_port elfin_ports[UART_NR] = { + { + iobase : (unsigned long)(UART0_CTL_BASE), + irq : IRQ_RXD0, + uartclk : 130252800, + fifosize : 64, + ops : &elfin_pops, + type : PORT_S3C24A0, + flags : ASYNC_BOOT_AUTOCONF, + }, +#ifndef CONFIG_BOARD_S3C24A0_SMDK + { + iobase : (unsigned long)(UART1_CTL_BASE), + irq : IRQ_RXD1, + uartclk : 130252800, + fifosize : 64, + ops : &elfin_pops, + type : PORT_S3C24A0, + flags : ASYNC_BOOT_AUTOCONF, + } +#endif /* !CONFIG_BOARD_S3C24A0_SMDK */ +}; + +void __init elfin_register_uart(int idx, int port) +{ + if (idx >= UART_NR) { + printk(KERN_ERR "%s: bad index number %d\n" + , __FUNCTION__, idx); + return; + } + elfin_ports[idx].uartclk = elfin_get_bus_clk(GET_PCLK); + + switch (port) { + case 0: + elfin_ports[idx].iobase = (unsigned long)(UART0_CTL_BASE); + elfin_ports[idx].irq = IRQ_RXD0; + break; + case 1: + elfin_ports[idx].iobase = (unsigned long)(UART1_CTL_BASE); + elfin_ports[idx].irq = IRQ_RXD1; + break; + default: + printk(KERN_ERR "%s : bad port number %d\n", __FUNCTION__, port); + } +} + + + +#ifdef CONFIG_SERIAL_S3C24A0_CONSOLE + +static void elfin_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = elfin_ports + co->index; + __xmit_string( port, s, count); +} + +static int __init elfin_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 0; + + port = uart_get_console(elfin_ports, UART_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +extern struct uart_driver elfin_reg; +static struct console elfin_cons = { + name : "ttyS", + write : elfin_console_write, + device : uart_console_device, + setup : elfin_console_setup, + flags : CON_PRINTBUFFER, + index : -1, + data : &elfin_reg, +}; + +static int __init elfin_console_init(void) +{ + register_console(&elfin_cons); + return 0; +} + +console_initcall(elfin_console_init); + +#define S3C24A0_CONSOLE &elfin_cons +#else /* CONFIG_SERIAL_S3C24A0_CONSOLE */ +#define S3C24A0_CONSOLE NULL +#endif /* CONFIG_SERIAL_S3C24A0_CONSOLE */ + + +static struct uart_driver elfin_reg = { + owner : THIS_MODULE, + driver_name : "ttyS", + dev_name : "ttyS", + major : TTY_MAJOR, + minor : 64, + nr : UART_NR, + cons : S3C24A0_CONSOLE, +}; + +static int __init elfinuart_init(void) +{ + int ret; + + printk("Initializing %s\n", __DRIVER_NAME); + ret = uart_register_driver(&elfin_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&elfin_reg, &elfin_ports[i]); + } + return ret; + +} + +static void __exit elfinuart_exit(void) +{ + uart_unregister_driver(&elfin_reg); +} + +module_init(elfinuart_init); +module_exit(elfinuart_exit); + + +MODULE_AUTHOR("Samsung"); +MODULE_DESCRIPTION("S3C24A0 generic serial port driver"); +MODULE_SUPPORTED_DEVICE("ttyS"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_s3c4510b.c b/drivers/serial/serial_s3c4510b.c new file mode 100644 index 00000000..7d0dcd47 --- /dev/null +++ b/drivers/serial/serial_s3c4510b.c @@ -0,0 +1,637 @@ +/* + * linux/drivers/serial/serial_s3c4510b.c + * + * Driver for S3C4510B serial ports + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Based on drivers/char/serial_amba.c + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define __DRIVER_NAME "Samsung S3C4510B Internal UART" + +#define _SDEBUG +#ifdef _SDEBUG +# define _DPRINTK(format, args...) \ + printk (KERN_INFO "%s():%05d "format".\n" , __FUNCTION__ , __LINE__ , ## args); +#else +# define _DPRINTK(format, args...) +#endif + +/** + ** + ** Internal(private) helper functions + ** + **/ + +static void __xmit_char(struct uart_port *port, const char ch) { + + struct uart_regs *uart = (struct uart_regs *)port->iobase; + + while( !uart->m_stat.bf.txBufEmpty); + + uart->m_tx = ch; + + if ( ch == '\n') { + while( !uart->m_stat.bf.txBufEmpty); + uart->m_tx = '\r'; + } + +} + +static void __xmit_string(struct uart_port *port, const char *p, int len) +{ + while( len-- > 0) { + __xmit_char( port, *p++); + } +} + +static void __s3c4510b_init(const struct uart_port *port, int baud) +{ + struct uart_regs *uart = (struct uart_regs *)port->iobase; + UART_CTRL uctrl; + UART_LINE_CTRL ulctrl; + UART_BAUD_DIV ubd; + + /* Reset the UART */ + /* control register */ + uctrl.ui = 0x0; + uctrl.bf.rxMode = 0x1; + uctrl.bf.rxIrq = 0x1; + uctrl.bf.txMode = 0x1; + uctrl.bf.DSR = 0x1; + uctrl.bf.sendBreak = 0x0; + uctrl.bf.loopBack = 0x0; + uart->m_ctrl.ui = uctrl.ui; + + /* Set the line control register into a safe sane state */ + ulctrl.ui = 0x0; + ulctrl.bf.wordLen = 0x3; /* 8 bit data */ + ulctrl.bf.nStop = 0x0; /* 1 stop bit */ + ulctrl.bf.parity = 0x0; /* no parity */ + ulctrl.bf.clk = 0x0; /* internal clock */ + ulctrl.bf.infra_red = 0x0; /* no infra_red */ + uart->m_lineCtrl.ui = ulctrl.ui; + + ubd.ui = 0x0; + + /* see table on page 10-15 in SAMSUNG S3C4510B manual */ + /* get correct divisor */ + switch( baud ? baud : 19200) { + + case 1200: + ubd.bf.cnt0 = 1301; + break; + + case 2400: + ubd.bf.cnt0 = 650; + break; + + case 4800: + ubd.bf.cnt0 = 324; + break; + + case 9600: + ubd.bf.cnt0 = 162; + break; + + case 19200: + ubd.bf.cnt0 = 80; + break; + + case 38400: + ubd.bf.cnt0 = 40; + break; + + case 57600: + ubd.bf.cnt0 = 26; + break; + + case 115200: + ubd.bf.cnt0 = 13; + break; + } + + uart->m_baudDiv.ui = ubd.ui; + uart->m_baudCnt = 0x0; + uart->m_baudClk = 0x0; + +} + +/** + ** + ** struct uart_ops functions below + ** + **/ + +static void __s3c4510b_stop_tx(struct uart_port *port) +{ + +} + + +static void __s3c4510b_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int count; + + // _DPRINTK("called with info = 0x%08x", (unsigned int) port); + + if ( port->x_char) { + __xmit_char( port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty( xmit) || uart_tx_stopped( port)) { + __s3c4510b_stop_tx( port); + return; + } + + count = port->fifosize >> 1; + do { + __xmit_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)) + __s3c4510b_stop_tx( port); +} + +static void __s3c4510b_start_tx(struct uart_port *port) +{ + __s3c4510b_tx_chars( port); +} + +static void __s3c4510b_send_xchar(struct uart_port *port, char ch) +{ + _DPRINTK("called with port = 0x%08x", (unsigned int) port); +} + +static void __s3c4510b_stop_rx(struct uart_port *port) +{ + struct uart_regs *uart = (struct uart_regs *)port->iobase; + UART_CTRL uctrl; + + _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + uctrl.ui = uart->m_ctrl.ui; + uctrl.bf.rxMode = 0x0; + uart->m_ctrl.ui = uctrl.ui; +} + +static void __s3c4510b_enable_ms(struct uart_port *port) +{ + _DPRINTK("called with port = 0x%08x", (unsigned int) port); +} + +static void __s3c4510b_rx_char(struct uart_port *port) +{ + struct uart_regs *uart = (struct uart_regs *)port->iobase; + struct tty_struct *tty = port->info->tty; + unsigned int ch; + UART_STAT status; + + status.ui = uart->m_stat.ui; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.work.func((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + ch = uart->m_rx & 0xFF; + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if ( status.bf.breakIrq) { + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + *tty->flip.flag_buf_ptr = TTY_BREAK; + } + else if ( status.bf.parity) { + port->icount.parity++; + *tty->flip.flag_buf_ptr = TTY_PARITY; + } + else if ( status.bf.frame) { + port->icount.frame++; + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + else if ( status.bf.overrun) { + port->icount.overrun++; + if ( tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + } + else { + /* no errors */ + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + +ignore_char: + + tty_flip_buffer_push(tty); + + +} + +static irqreturn_t __s3c4510b_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ +// _DPRINTK("called with irq = 0x%08x", irq); + + struct uart_port *port = dev_id; + + LED_SET(2); + __s3c4510b_rx_char( port); + LED_CLR(2); + + return IRQ_HANDLED; +} + +static irqreturn_t __s3c4510b_tx_int(int irq, void *dev_id, struct pt_regs *regs) +{ +// _DPRINTK("called with irq = 0x%08x", irq); + + struct uart_port *port = dev_id; + + LED_SET(1); + __s3c4510b_start_tx( port); + LED_CLR(1); + + return IRQ_HANDLED; +} + +static unsigned int __s3c4510b_tx_empty(struct uart_port *port) +{ + struct uart_regs *uart = (struct uart_regs *)port->iobase; + +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + return uart->m_stat.bf.txBufEmpty ? 1 : 0; +} + +static unsigned int __s3c4510b_get_mctrl(struct uart_port *port) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + return 0; +} + +static void __s3c4510b_set_mctrl(struct uart_port *port, u_int mctrl) +{ +// _DPRINTK("called with port = 0x%08x, mctrl = 0x%08x", (unsigned int) port, mctrl); +} + +static void __s3c4510b_break_ctl(struct uart_port *port, int break_state) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); +} + +static struct irqaction __rx_irqaction[UART_NR] = { + { + name: "serial0_rx", + flags: SA_INTERRUPT, + handler: __s3c4510b_rx_int, + }, + { + name: "serial1_rx", + flags: SA_INTERRUPT, + handler: __s3c4510b_rx_int, + }, +}; + +static struct irqaction __tx_irqaction[UART_NR] = { + { + name: "serial0_tx", + flags: SA_INTERRUPT, + handler: __s3c4510b_tx_int, + }, + { + name: "serial1_tx", + flags: SA_INTERRUPT, + handler: __s3c4510b_tx_int, + }, +}; + +static int __s3c4510b_startup(struct uart_port *port) +{ + int status; + +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + __s3c4510b_init(port, 19200); + + /* + * Allocate the IRQs for TX and RX + */ + __tx_irqaction[port->line].dev_id = (void *)port; + __rx_irqaction[port->line].dev_id = (void *)port; + + status = setup_irq( port->irq, &__tx_irqaction[port->line]); + if ( status) { + printk( KERN_ERR "Unabled to hook interrupt for serial %d TX\n", port->line); + return status; + } + + status = setup_irq( port->irq+1, &__rx_irqaction[port->line]); + if ( status) { + printk( KERN_ERR "Unabled to hook interrupt for serial %d RX\n", port->line); + return status; + } + + /* + * Finally, enable interrupts + */ + spin_lock_irq( &port->lock); + INT_ENABLE( port->irq); + INT_ENABLE( port->irq+1); + spin_unlock_irq( &port->lock); + + return 0; +} + +static void __s3c4510b_shutdown(struct uart_port *port) +{ + struct uart_regs *uart = (struct uart_regs *)port->iobase; + + // _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + INT_DISABLE( port->irq); + INT_DISABLE( port->irq+1); + + /* turn off TX/RX */ + uart->m_ctrl.ui = 0x0; + +} + +static void __s3c4510b_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + + /** + ** Ignore -- only 19200 baud supported + **/ + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, 19200); + +} + +static void __s3c4510b_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +{ +// _DPRINTK("called with port = 0x%08x, state = %u", (unsigned int) port, state); +} + +static int __s3c4510b_set_wake(struct uart_port *port, unsigned int state) +{ +// _DPRINTK("called with port = 0x%08x, state = %u", (unsigned int) port, state); + return 0; +} + +static const char *__s3c4510b_type(struct uart_port *port) +{ + return __DRIVER_NAME; +} + + +static void __s3c4510b_release_port(struct uart_port *port) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); +} + +static int __s3c4510b_request_port(struct uart_port *port) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + return 0; +} + +static void __s3c4510b_config_port(struct uart_port *port, int config) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); +} + +static int __s3c4510b_verify_port(struct uart_port *port, struct serial_struct *serial) +{ +// _DPRINTK("called with port = 0x%08x", (unsigned int) port); + return 0; +} + +#if 0 +static int __s3c4510b_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) +{ +// _DPRINTK("called with port = 0x%08x, cmd %u, arg 0x%08lx", (unsigned int) port, cmd, arg); + return 0; +} +#endif + +static struct uart_ops s3c4510b_pops = { + tx_empty: __s3c4510b_tx_empty, + set_mctrl: __s3c4510b_set_mctrl, + get_mctrl: __s3c4510b_get_mctrl, + stop_tx: __s3c4510b_stop_tx, + start_tx: __s3c4510b_start_tx, + send_xchar: __s3c4510b_send_xchar, + stop_rx: __s3c4510b_stop_rx, + enable_ms: __s3c4510b_enable_ms, + break_ctl: __s3c4510b_break_ctl, + startup: __s3c4510b_startup, + shutdown: __s3c4510b_shutdown, + set_termios: __s3c4510b_set_termios, + pm: __s3c4510b_pm, + set_wake: __s3c4510b_set_wake, + type: __s3c4510b_type, + release_port: __s3c4510b_release_port, + request_port: __s3c4510b_request_port, + config_port: __s3c4510b_config_port, + verify_port: __s3c4510b_verify_port, +// ioctl: __s3c4510b_ioctl, +}; + + +static struct uart_port __s3c4510b_ports[UART_NR] = { + { + iobase: UART0_BASE, + line: 0, + irq: INT_UARTTX0, + fifosize: 1, + ops: &s3c4510b_pops, + ignore_status_mask: 0x0000000F, + type: PORT_S3C4510B, + }, + { + iobase: UART1_BASE, + line: 1, + irq: INT_UARTTX1, + fifosize: 1, + ops: &s3c4510b_pops, + ignore_status_mask: 0x0000000F, + type: PORT_S3C4510B, + } +}; + +#ifdef CONFIG_SERIAL_S3C4510B_CONSOLE +/************** console driver *****************/ + +static void __s3c4510b_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = &__s3c4510b_ports[co->index]; + + __xmit_string( port, s, count); + +} + +static int __init __s3c4510b_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 19200; + int bits = 8; + int parity = 'n'; + int flow = 0; + + /* + * 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(__s3c4510b_ports, UART_NR, co); + +// _DPRINTK("using port = 0x%08x", (unsigned int) port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + __s3c4510b_init(port, baud); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +extern struct uart_driver __s3c4510b_driver; +static struct console __s3c4510b_console = { + name: "ttyS", + write: __s3c4510b_console_write, + device: uart_console_device, + setup: __s3c4510b_console_setup, + flags: CON_PRINTBUFFER, + index: -1, + data: &__s3c4510b_driver, +}; + +static int __init __s3c4510b_console_init(void) +{ + register_console(&__s3c4510b_console); + return 0; +} + +console_initcall(__s3c4510b_console_init); + +#endif /* CONFIG_SERIAL_S3C4510B_CONSOLE */ + + +static struct uart_driver __s3c4510b_driver = { + owner: THIS_MODULE, + driver_name: __DRIVER_NAME, + dev_name: "ttyS", + major: TTY_MAJOR, + minor: 64, + nr: UART_NR, +#ifdef CONFIG_SERIAL_S3C4510B_CONSOLE + cons: &__s3c4510b_console, +#endif +}; + +static int __init __s3c4510b_serial_init(void) +{ + + int status, i; + +// _DPRINTK("initializing driver with drv = 0x%08x", (unsigned int) &__s3c4510b_driver); + + status = uart_register_driver( &__s3c4510b_driver); + + if ( status) { + _DPRINTK("uart_register_driver() returned %d", status); + } + + for ( i = 0; i < UART_NR; i++) { + status = uart_add_one_port( &__s3c4510b_driver, &__s3c4510b_ports[i]); + if ( status) { + _DPRINTK("uart_add_one_port(%d) returned %d", i, status); + } + } + + return 0; +} + +module_init(__s3c4510b_serial_init); + diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index cfcc3caf..36956ed2 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -42,6 +42,15 @@ #include #endif +#ifdef CONFIG_LEDMAN +#include +#endif + +#include +#include +#include +#include + #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) #include #include @@ -78,6 +87,10 @@ struct sci_port { /* Break timer */ struct timer_list break_timer; int break_flag; + +#if defined(CONFIG_SH_SECUREEDGE5410) + int open; +#endif }; #ifdef CONFIG_SH_KGDB @@ -200,6 +213,41 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count) } #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ +#if defined(CONFIG_SH_SECUREEDGE5410) +#include +struct timer_list sci_timer_struct; +static unsigned char sci_dcdstatus[2]; + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * to monitor the state of the DCD lines - since they have no edge + * sensors and interrupt generators. + */ +static void sci_timer(unsigned long data) +{ + unsigned short s, i; + unsigned char dcdstatus[2]; + + s = SECUREEDGE_READ_IOPORT(); + dcdstatus[0] = !(s & 0x10); + dcdstatus[1] = !(s & 0x1); + + for (i = 0; i < 2; i++) { + if (dcdstatus[i] != sci_dcdstatus[i]) { + if (sci_ports[i].open != 0) { + uart_handle_dcd_change(&sci_ports[i].port, dcdstatus[i]); + } + } + sci_dcdstatus[i] = dcdstatus[i]; + } + + sci_timer_struct.expires = jiffies + HZ/25; + add_timer(&sci_timer_struct); +} + +#endif + + #ifdef CONFIG_SH_KGDB static int kgdb_sci_getchar(void) { @@ -385,6 +433,11 @@ static void sci_transmit_chars(struct uart_port *port) unsigned short ctrl; int count; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + port == &sci_ports[0].port ? LEDMAN_COM1_TX : LEDMAN_COM2_TX); +#endif + status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { ctrl = sci_in(port, SCSCR); @@ -458,6 +511,11 @@ static inline void sci_receive_chars(struct uart_port *port) if (!(status & SCxSR_RDxF(port))) return; +#ifdef CONFIG_LEDMAN + ledman_cmd(LEDMAN_CMD_SET, + port == &sci_ports[0].port ? LEDMAN_COM1_RX : LEDMAN_COM2_RX); +#endif + while (1) { #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) @@ -857,6 +915,36 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ /* If you have signals for DTR and DCD, please implement here. */ +#if defined(CONFIG_SH_SECUREEDGE5410) + int flags; + + local_irq_save(flags); + switch (port->line) { + case 1: /* port 1 only */ + if (mctrl & TIOCM_DTR) + SECUREEDGE_WRITE_IOPORT(0x0000, 0x0080); + else + SECUREEDGE_WRITE_IOPORT(0x0080, 0x0080); + if ((sci_in(port, SCFCR) & SCFCR_MCE) == 0) { + if (mctrl & TIOCM_RTS) + sci_out(port, SCSPTR, sci_in(port, SCSPTR) & ~0x40); + else + sci_out(port, SCSPTR, sci_in(port, SCSPTR) | 0x40); + } + break; + case 0: /* port 0 only */ + if (mctrl & TIOCM_DTR) + SECUREEDGE_WRITE_IOPORT(0x0000, 0x0200); + else + SECUREEDGE_WRITE_IOPORT(0x0200, 0x0200); + if (mctrl & TIOCM_RTS) + SECUREEDGE_WRITE_IOPORT(0x0000, 0x0100); + else + SECUREEDGE_WRITE_IOPORT(0x0100, 0x0100); + break; + } + local_irq_restore(flags); +#endif } static unsigned int sci_get_mctrl(struct uart_port *port) @@ -864,6 +952,46 @@ static unsigned int sci_get_mctrl(struct uart_port *port) /* This routine is used for geting signals of: DTR, DCD, DSR, RI, and CTS/RTS */ +#if defined(CONFIG_SH_SECUREEDGE5410) + int rc = TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; + + switch (port->line) { + case 1: /* port 1 only */ + { + unsigned short s = SECUREEDGE_READ_IOPORT(); + rc = TIOCM_RTS|TIOCM_DSR|TIOCM_CTS; + + if ((sci_in(port, SCFCR) & SCFCR_MCE) == 0) { + if (sci_in(port, SCSPTR) & 0x0040) + rc &= ~TIOCM_RTS; + if (sci_in(port, SCSPTR) & 0x0010) + rc &= ~TIOCM_CTS; + } + + if ((s & 0x0001) == 0) + rc |= TIOCM_CAR; + if ((SECUREEDGE_READ_IOPORT() & 0x0080) == 0) + rc |= TIOCM_DTR; + } + break; + case 0: /* port 0 only */ + { + unsigned short s = SECUREEDGE_READ_IOPORT(); + rc = TIOCM_DSR; + + if ((s & 0x0010) == 0) + rc |= TIOCM_CAR; + if ((s & 0x0004) == 0) + rc |= TIOCM_CTS; + if ((SECUREEDGE_READ_IOPORT() & 0x0200) == 0) + rc |= TIOCM_DTR; + if ((SECUREEDGE_READ_IOPORT() & 0x0100) == 0) + rc |= TIOCM_RTS; + } + break; + } + return(rc); +#endif return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; } @@ -921,6 +1049,12 @@ static int sci_startup(struct uart_port *port) { struct sci_port *s = &sci_ports[port->line]; +#if defined(CONFIG_SH_SECUREEDGE5410) + sci_ports[port->line].open++; +#endif +#if defined(__H8300S__) + h8300_sci_enable(port, sci_enable); +#endif if (s->enable) s->enable(port); @@ -939,6 +1073,12 @@ static void sci_shutdown(struct uart_port *port) sci_stop_tx(port); sci_free_irq(s); +#if defined(__H8300S__) + h8300_sci_enable(port, sci_disable); +#endif +#if defined(CONFIG_SH_SECUREEDGE5410) + sci_ports[port->line].open--; +#endif if (s->disable) s->disable(port); } @@ -1434,6 +1574,21 @@ static int __init sci_init(void) ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { + +#if defined(CONFIG_SH_SECUREEDGE5410) + unsigned short s; + + init_timer(&sci_timer_struct); + sci_timer_struct.function = sci_timer; + sci_timer_struct.data = 0; + sci_timer_struct.expires = jiffies + HZ/25; + add_timer(&sci_timer_struct); + + s = SECUREEDGE_READ_IOPORT(); + sci_dcdstatus[0] = !(s & 0x10); + sci_dcdstatus[1] = !(s & 0x1); +#endif + ret = platform_driver_register(&sci_driver); if (unlikely(ret)) uart_unregister_driver(&sci_uart_driver); @@ -1444,6 +1599,9 @@ static int __init sci_init(void) static void __exit sci_exit(void) { +#if defined(CONFIG_SH_SECUREEDGE5410) + del_timer(&sci_timer_struct); +#endif platform_driver_unregister(&sci_driver); uart_unregister_driver(&sci_uart_driver); } diff --git a/drivers/spi/DS1305RTC.c b/drivers/spi/DS1305RTC.c new file mode 100644 index 00000000..da59b68d --- /dev/null +++ b/drivers/spi/DS1305RTC.c @@ -0,0 +1,252 @@ +/*************************************************************************** + DS1305RTC.c + DS1305 RTC character driver for uClinux mcfqspi control + These functions rely on the MCF_QSPI module for the SPI layer. + Modified from the IPAC DS1305 module for hcs12 communication + with the DS1305 + --------------------------- + begin : Thur April 28 2005 + email : ngustavson@emacinc.com + (C) Copyright 2005 : EMAC.Inc - www.emacinc.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + MODULE_LICENSE("GPL"); + +/*************************************************************************** + * External functions + ***************************************************************************/ +extern qspi_dev *qspi_create_device(void); +extern int qspi_destroy_device(qspi_dev *device); +extern ssize_t qspi_internal_read(qspi_dev *dev,char *buffer, size_t length, + loff_t *off,int qcr_cs); +extern ssize_t qspi_internal_write(qspi_dev *dev,const char *buffer, size_t length, + loff_t *off,int qcr_cs); +extern u16 qspi_BAUD(int desired); +extern void qspi_mutex_down(void); +extern void qspi_mutex_up(void); + + +/*!Write to a RTC register +@param device qspi device the RTC1305 belongs too +@param reg the register to write to(from the enumerated registers above) +@param the data to write to it +@return SUCCESS +*/ +static int RTC_Write_Register(rtc_qspi_device *dev,int reg, u8 data) +{ +u8 output[2]; +output[0] = reg + WRITE_OFFSET; +output[1] = data; +RTC_CE_ON(); +qspi_internal_write(dev->qspi, output, sizeof(output),0,0); +RTC_CE_OFF(); +return SUCCESS; +} + +/*!Read from a RTC register +@param device qspi device the RTC1305 belongs too +@param reg he register to write to(from the enumerated registers above) +@return the byte that was read +*/ +static u8 RTC_Read_Register(rtc_qspi_device *dev,int reg) +{ +u8 buffer[2]; +buffer[0] = reg; +buffer[1] = 0; +dev->qspi->read_data.length = sizeof(buffer); +dev->qspi->read_data.buf = buffer; + +RTC_CE_ON(); +qspi_internal_read(dev->qspi,buffer, sizeof(buffer),0,0); +RTC_CE_OFF(); + +dev->qspi->read_data.length=0; +dev->qspi->read_data.buf =NULL; + +return buffer[1]; +} + +static rtc_qspi_device *RTC_create_device(void) +{ +rtc_qspi_device *dev; +qspi_dev *spi = qspi_create_device(); + +if(spi==NULL) + return(NULL); + +if ((dev = kmalloc(sizeof(rtc_qspi_device), GFP_KERNEL)) == NULL) { + return(NULL); +} + +dev->qspi = spi; + +spi->poll_mod = 1; +spi->baud = qspi_BAUD(2000000); /* intial baud rate 2M */ +spi->cpha = 1; /* SPI clock phase */ + +RTC_CE_SETUP(); + +RTC_Write_Register(dev,CONTROL,INTCN); +return dev; +} + + +static rtc_qspi_device *RTC_destroy_device(rtc_qspi_device *dev){ +if(dev==NULL) + return NULL; +qspi_destroy_device(dev->qspi); +kfree(dev); +return NULL; +} +/*!Get the current time from the RTC +This function reads the current time stored in the RTC's internal registers. +Alternatively each individual register can be returned using the RTC_ macros below +@param time a rtc_time structure that GetTime fills with data +@return SUCCESS +*/ +static int RTC_GetTime(rtc_qspi_device *dev,struct rtc_time *time) +{ +time->tm_sec = (RTC_SECONDS(dev)); +time->tm_min = (RTC_MINUTES(dev)); +time->tm_hour = (RTC_HOURS(dev)); +time->tm_wday = (RTC_DAY(dev)); +time->tm_mday = (RTC_DATE(dev)); +time->tm_mon = (RTC_MONTH(dev)); +time->tm_year = (RTC_YEAR(dev)); +time->tm_sec = RTC2TIME(time->tm_sec); +time->tm_min = RTC2TIME(time->tm_min); +time->tm_hour = RTC2TIME(time->tm_hour); +time->tm_wday = RTC2TIME(time->tm_wday); +time->tm_mday = RTC2TIME(time->tm_mday); +time->tm_mon = RTC2TIME(time->tm_mon); +time->tm_year = RTC2TIME(time->tm_year); +return SUCCESS; +} + +/*!Set the current time of the RTC +This function sets the current time stored in the RTC's internal registers. +Alternatively each individual register can be written using the +RTC_Write_Register function. +@param time a rtc_time structure SetTime writes to the clock +@return SUCCESS +@see RTC_Write_Register function. +*/ +static int RTC_SetTime(rtc_qspi_device *dev,struct rtc_time *time) +{ +RTC_SET_SECONDS(dev,time->tm_sec); +RTC_SET_MINUTES(dev,time->tm_min); +RTC_SET_HOURS(dev,time->tm_hour); +RTC_SET_DAY(dev,time->tm_wday); +RTC_SET_DATE(dev,time->tm_mday); +RTC_SET_MONTH(dev,time->tm_mon); +RTC_SET_YEAR(dev,time->tm_year); +return SUCCESS; +} + + +static int ds1305_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + rtc_qspi_device *dev = filp->private_data; + struct rtc_time wtime; + + switch(cmd){ + + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + memset(&wtime, 0, sizeof(struct rtc_time)); + RTC_GetTime(dev,&wtime); + if(copy_to_user((void __user *)arg, &wtime, sizeof wtime)) + return -EFAULT; + return 0; + } + case RTC_SET_TIME: /* Set the RTC */ + { + if (copy_from_user(&wtime, (struct rtc_time __user *)arg, + sizeof(struct rtc_time))) + return -EFAULT; + RTC_SetTime(dev,&wtime); + return 0; + } + + default: + return -EINVAL; + } + +return 0; +} + + +static int ds1305_open (struct inode *inode, struct file *filp){ +rtc_qspi_device *dev = RTC_create_device(); +if(dev==NULL) + return -ENOMEM; +filp->private_data = dev; +return 0; +} + +static int ds1305_release(struct inode *inode, struct file *filp){ +RTC_destroy_device(filp->private_data); +return 0; +} + +struct file_operations ds1305_fops={ + ioctl: ds1305_ioctl, + open: ds1305_open, + release: ds1305_release, +}; + +static struct miscdevice ds1305rtc_dev= +{ + RTC_MINOR, + DSNAME , + &ds1305_fops +}; + + +static int __init ds1305_init(void){ + +//SET_MODULE_OWNER(&ds1305_fops); + + /* the drivers (main) function*/ + +printk(" "DSNAME " driver version " DS_DRIVER_V " (c) " __DATE__ "\n"); + printk(" N.Z. Gustavson (ngustavson@emacinc.com), EMAC.inc\n"); + +//DSMajor = register_chrdev(DSMAJORNUM, DSNAME, &ds1305_fops); +if (misc_register(&ds1305rtc_dev)) { +printk(DSNAME" driver failed to register"); +return -ENODEV; +} + +printk(DSNAME" Driver Registered\n"); +return 0; +} + +static void __exit ds1305_exit (void){ +//unregister_chrdev(DSMajor,DSNAME); +misc_deregister(&ds1305rtc_dev); +printk(DSNAME" driver unloaded\n"); +} + +module_init(ds1305_init); +module_exit(ds1305_exit); +MODULE_ALIAS_MISCDEV(RTC_MINOR); + diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 23334c8b..671e2977 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -106,6 +106,28 @@ config SPI_S3C24XX_GPIO # # Add new SPI master controllers in alphabetical order above this line # +config MCFQSPI + tristate "Coldfire Queued SPI" + depends on SPI + help + Say Y here to compile in support for the coldfire Queued SPI driver. + This driver provides a standard character driver interface, and + provides symbols required for some other drivers on the SoM-5282EM. + + This support is also available as a module. If so, the module + will be called mcf_qspi. + +config DS1305 + tristate "DS1305 Real time Clock" + depends on MCFQSPI + help + Say Y here to compile in support for the qspi stacked DS1305 real + time clock driver. This driver stacks on top of the mcf_qspi driver + and provides a misc RTC driver, which takes the standard RTC minor + number. + + This support is also available as a module. If so, the module will + be called DS1305RTC. config SPI_S3C24XX @@ -131,3 +153,4 @@ comment "SPI Protocol Masters" endmenu # "SPI support" + diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8f4cb679..c2f8be89 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,6 +17,8 @@ obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o +obj-$(CONFIG_MCFQSPI) += mcf_qspi.o +obj-$(CONFIG_DS1305) += DS1305RTC.o # ... add above this line ... # SPI protocol drivers (device/link on bus) @@ -27,3 +29,4 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o # SPI slave drivers (protocol for that link) # ... add above this line ... + diff --git a/drivers/spi/mcf_qspi.c b/drivers/spi/mcf_qspi.c new file mode 100644 index 00000000..95647a1e --- /dev/null +++ b/drivers/spi/mcf_qspi.c @@ -0,0 +1,1107 @@ +/************************************************************************/ +/* */ +/* mcf_qspi.c - QSPI driver for MCF5272, MCF5235, MCF5282 */ +/* */ +/* (C) Copyright 2001, Wayne Roberts (wroberts1@home.com) */ +/* */ +/* Driver has an 8bit mode, and a 16bit mode. */ +/* Transfer size QMR[BITS] is set thru QSPIIOCS_BITS. */ +/* When size is 8, driver works normally: */ +/* a char is sent for every transfer */ +/* When size is 9 to 16bits, driver reads & writes the QDRs with */ +/* the buffer cast to unsigned shorts. The QTR & QRR registers can */ +/* be filled with up to 16bits. The length passed to read/write must */ +/* be of the number of chars (2x number of shorts). This has been */ +/* tested with 10bit a/d and d/a converters. */ +/* */ +/* * QSPIIOCS_READDATA: */ +/* data to send out during read */ +/* * all other ioctls are global */ +/* -------------------------------------------------------------------- */ +/* Ported to linux-2.4.x by Ron Fial (ron@fial.com) August 26,2002 */ +/* */ +/* Added new include files */ +/* Added module_init(),exit(), */ +/* qspi_read(),qspi_write(): Revised qspi_read & write argument */ +/* processing to handle new *filep argument. Changed i_rdev access */ +/* to use filep->f_dentry->d_inode->i_rdev Changed memcpy_fromfs() */ +/* to memcpy(). */ +/* Added '__init' to compiled-in init routine for memory recovery */ +/* Added '__exit' for loadable-driver module cleanup routine */ +/* changed register_chrdev to devfs_register_chrdev */ +/* changed unregister_chrdev to devfs_unregister_chrdev */ +/* Changed various declarations from int to ssize_t or loff_t */ +/* -------------------------------------------------------------------- */ +/* Changed interruptible_sleep_on to sleep_on so the driver has */ +/* chance to finish the current transfer before application */ +/* quits when typing '^C'. Otherwise a write collision will */ +/* most likely occur. */ +/* Added safe_flags(); cli; and restore_flags() according to */ +/* gerg@snapgear.com. Otherwise in some cases (higher clock */ +/* rates) the transfer is finished before the current process */ +/* is put to sleep and therefore never wakes up again. */ +/* 09/12/2002 richard@opentcp.org */ +/* -------------------------------------------------------------------- */ +/* 02/06/2003 josef.baumgartner@telex.de */ +/* */ +/* Renamed cleanup_module() to qspi_exit() to be able to */ +/* compile as module. */ +/* Removed init_module() because module_init(qspi_init) does all */ +/* we need. */ +/* Changed */ +/* SPI register settings will be saved for each instance to be able */ +/* to use different communication settings for different tasks. */ +/* An ioctl() does not longer write directly to the SPI registers. */ +/* It saves the settings which will be copied into the SPI */ +/* registers on every read()/write(). */ +/* Added MODULE_LICENSE("GPL") to avoid tainted kernel message. */ +/* I think it is GPL?? There's no comment about this?? */ +/* Added polling mode */ +/* Increases performance for small data transfers. */ +/* Added odd mode */ +/* If an odd number of bytes is transfered and 16bit transfers are */ +/* used, the last byte is transfered in byte mode. */ +/* Added dsp mode */ +/* If dsp mode is set, transfers will be limited to 15 bytes */ +/* instead of 16. This ensures that DSPs with 24bit words get */ +/* whole words within one transfer. */ +/* -------------------------------------------------------------------- */ +/* 16/09/2003 ivan.zanin@bluewin.ch */ +/* */ +/* Changed init and exit code to support the MCF5249 */ +/* -------------------------------------------------------------------- */ +/* Oct 19, 2004 jsujjavanich@syntech-fuelmaster.com */ +/* */ +/* Adjusted minor number detection to work with one dev per QSPI_CS */ +/* -------------------------------------------------------------------- */ +/* 17/11/2004 chris_jones_oz@yahoo.com.au */ +/* */ +/* Changed init and exit code to support the MCF5282 */ +/* -------------------------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/* Feb 3, 2005 ngustavson@emacinc.com */ +/* */ +/* Modularized function calls support kernel2kernel calls */ +/* -------------------------------------------------------------------- */ +/************************************************************************/ + + + +/* ********************************************************************** +Chapter 14. (excerpt) Queued Serial Peripheral Interface (QSPI) Module + From: http://e-www.motorola.com/brdata/PDFDB/docs/MCF5272UM.pdf + +The following steps are necessary to set up the QSPI 12-bit data transfers +and a QSPI_CLK of 4.125 MHz. The QSPI RAM is set up for a queue of 16 +transfers. All four QSPI_CS signals are used in this example. + +1. Enable all QSPI_CS pins on the MCF5272. Write PACNT with 0x0080_4000 to +enable QSPI_CS1 and QSPI_CS3.Write PDCNT with 0x0000_0030 to enable QSPI_CS2. + +2. Write the QMR with 0xB308 to set up 12-bit data words with the data +shifted on the falling clock edge, and a clock frequency of 4.125 MHz +(assuming a 66-MHz CLKIN). + +3. Write QDLYR with the desired delays. + +4. Write QIR with 0xD00F to enable write collision, abort bus errors, and +clear any interrupts. + +5. Write QAR with 0x0020 to select the first command RAM entry. + +6. Write QDR with 0x7E00, 0x7E00, 0x7E00, 0x7E00, 0x7D00, 0x7D00, 0x7D00, +0x7D00, 0x7B00, 0x7B00, 0x7B00, 0x7B00, 0x7700, 0x7700, 0x7700, and 0x7700 +to set up four transfers for each chip select. The chip selects are active +low in this example. NOTE: QDR value auto-increments after each write. + +7. Write QAR with 0x0000 to select the first transmit RAM entry. + +8. Write QDR with sixteen 12-bit words of data. + +9. Write QWR with 0x0F00 to set up a queue beginning at entry 0 and ending +at entry 15. + +10. Set QDLYR[SPE] to enable the transfers. + +11.Wait until the transfers are complete. QIR[SPIF] is set when the +transfers are complete. + +12. Write QAR with 0x0010 to select the first receive RAM entry. + +13. Read QDR to get the received data for each transfer. NOTE: QDR +auto-increments. + +14. Repeat steps 5 through 13 to do another transfer. + +************************************************************************* */ + +/** +* Includes +*------------------------------------------------------------------------------- +*/ +#define EXPORT_SYMTAB + +#include /* gets us MCF_MBAR value */ +#include /* MCFSIM offsets */ +#include +#include /* cli() and friends */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Include versioning info, if needed */ +#if (defined(MODULE) && defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)) +#define MODVERSIONS +#endif + +#if defined(MODVERSIONS) +#include +#endif + +#include + +int __init qspi_init(void); +static int init(void); +void __exit qspi_exit(void); + + +/** +* Declarations and global variables +*------------------------------------------------------------------------------- +*/ +#define DEVICE_NAME "qspi" + +MODULE_LICENSE("GPL"); +/* struct wait_queue *wqueue; */ +static DECLARE_WAIT_QUEUE_HEAD(wqueue); /* use ver 2.4 static declaration - ron */ +/* or should we use wait_queue_heat_t *wqueue ?? see page 141 */ + +static unsigned char dbuf[1024]; + +/* static struct semaphore sem = MUTEX; */ + +static DECLARE_MUTEX(sem); + + + +/** +* EXPORTED symbols +*------------------------------------------------------------------------------- +*/ +EXPORT_SYMBOL(qspi_mutex_down); +EXPORT_SYMBOL(qspi_mutex_up); +EXPORT_SYMBOL(qspi_create_device); +EXPORT_SYMBOL(qspi_destroy_device); +EXPORT_SYMBOL(qspi_internal_read); +EXPORT_SYMBOL(qspi_internal_write); +EXPORT_SYMBOL(qspi_control); +EXPORT_SYMBOL(qspi_BAUD); + +/** + * Kernel function calls (EXPORTED) + * These functions provide the interface to the hardware. + * They may only be called from Kernel space. + * To use them directly from user space, the standard legacy char driver + * API has been maintained in wrapper functions. + * ----------------------------------------------------------------------------- + */ + + + /** + * qspi_mutex_down. + * get in line for the qspi mutex + * the internal kernel calls do not hold the mutex themselves and so down/up + * must be called manually. This introduces a new level of complexity, + * but is required, as it may be necessary for some drivers to + * hold the mutex through more than one transaction. + */ + void qspi_mutex_down(void){ + down_interruptible(&sem); + } + /** + * qspi_mutex up + * signal the qspi mutex. + * see qspi_mutex_down + */ + void qspi_mutex_up(void){ + up(&sem); + } + +/** + * qspi_create_device + * Create a QSPI device. + * Configuration information is stored in this device structure, which + * is used by the read and write calls, to dynamically change the SPI's + * configuration(bitrate, CPOL, etc...) + * The elements of the structure are modifyable via control calls. + * This function allocates the space for the device with Kmalloc, so if + * the device is not destroyed(qspi_destroy_device, it will result in a + * memory leak. + * @return a newly allocated and initialized qspi device + */ +qspi_dev *qspi_create_device(void){ +qspi_dev *dev; + + if ((dev = kmalloc(sizeof(qspi_dev), GFP_KERNEL)) == NULL) { + return(NULL); + } + + /* set default values */ + dev->read_data.length = 0; + dev->read_data.buf = NULL; + dev->read_data.loop = 0; + dev->poll_mod = 0; /* interrupt mode */ + dev->bits = 8; + dev->baud = qspi_BAUD(DEFAULT_BIT_RATE); + dev->cpol = 0; + dev->cpha = 0; + dev->qcr_cont = 1; + dev->dsp_mod = 0; /* no DSP mode */ + dev->odd_mod = 0; /* no ODD mode */ + dev->qcd = 17; + dev->dtl = 1; + + return(dev); +} +/** + * qspi_destroy device + * free a previously created qspi device + * @param device the device to destroy + */ +int qspi_destroy_device(qspi_dev *device){ + kfree(device); +return 0; +} + +/** + * qspi_internal_read + * Read a block of SPI data into an array + * SPI mode is set at the beginning of the transfer to be whatever is + * stored in the device structure + * This function is not thread safe, qspi_mutex_up/down should be used. + * @param dev device node containing transfer mode information + * @buffer kernel space array to transfer the data into + * @length amount of data to transfer should not be >sizeof(buffer) + * @off unused + * @qcr_cs slave select bitmap to use, ie. 3 would toggle SS0 and 1 + */ +ssize_t qspi_internal_read(qspi_dev *dev,char *buffer, size_t length, + loff_t *off,int qcr_cs){ + int total = 0; + int i = 0; + int max_trans; + unsigned char bits; + unsigned char word = 0; + //unsigned long flag; + int rdi = 0; + + /* set the register with default values */ + QMR = QMR_MSTR | + (dev->dohie << 14) | + (dev->bits << 10) | + (dev->cpol << 9) | + (dev->cpha << 8) | + (dev->baud); + + QDLYR = (dev->qcd << 8) | dev->dtl; + + if (dev->dsp_mod) + max_trans = 15; + else + max_trans = 16; + + + bits = dev->bits % 0x10; + if (bits == 0 || bits > 0x08) + word = 1; /* 9 to 16bit transfers */ + + //printk("\n READ driver -- ioctl xmit data fm dev->read_data.buf array %x %x %x %x \n",dev->read_data.buf[0],dev->read_data.buf[1],dev->read_data.buf[2],dev->read_data.buf[3]); + + while (i < length) { + unsigned short *sp = (unsigned short *)&buffer[i]; + unsigned char *cp = &buffer[i]; + unsigned short *rd_sp = (unsigned short *)dev->read_data.buf; + int x; + int n; + + QAR = TX_RAM_START; /* address first QTR */ + QSPIDEBUG("writing from read buffer "); + for (n = 0; n < max_trans; n++) { + if (rdi != -1) { + if (word) { + QDR = rd_sp[rdi++]; + if (rdi == dev->read_data.length >> 1) + rdi = dev->read_data.loop ? 0 : -1; + } else { + QSPIDEBUG("%x ",dev->read_data.buf[rdi]); + QDR = dev->read_data.buf[rdi++]; + if (rdi == dev->read_data.length) + rdi = dev->read_data.loop ? 0 : -1; + } + } else + QDR = 0; + + i++; + if (word) + i++; + if (i > length) + break; + } + QSPIDEBUG("\n"); + + + QAR = COMMAND_RAM_START; /* address first QCR */ + for (x = 0; x < n; x++) { + /* QCR write */ + if (dev->qcr_cont) { + if (x == n - 1 && i == length) + QDR = QCR_SETUP | qcr_cs; /* last transfer */ + else + QDR = QCR_CONT | QCR_SETUP | qcr_cs; + } else + QDR = QCR_SETUP | qcr_cs; + } + + QWR = QWR_CSIV | ((n - 1) << 8); + + /* check if we are using polling mode. Polling increases + * performance for small data transfers but is dangerous + * if we stay too long here, locking other tasks!! + */ + if (dev->poll_mod) { + QIR = QIR_SETUP_POLL; + QDLYR |= QDLYR_SPE; + + while ((QIR & QIR_SPIF) != QIR_SPIF) + ; + QIR = QIR | QIR_SPIF; + } else { + QIR = QIR_SETUP; + //save_flags(flag); cli(); // like in write function - don't think we need this + + QDLYR |= QDLYR_SPE; +// interruptible_sleep_on(&wqueue); + sleep_on(&wqueue); // changed richard@opentcp.org + //restore_flags(flag); // like in write function + + } + + QAR = RX_RAM_START; /* address: first QRR */ + if (word) { + /* 9 to 16bit transfers */ + for (x = 0; x < n; x++) { + *sp = *(volatile unsigned short *)(MCF_MBAR + MCFSIM_QDR); + sp++; + } + } else { + /* 8bit transfers */ + QSPIDEBUG("8 bit read: "); + for (x = 0; x < n; x++){ + *cp = *(volatile unsigned short *)(MCF_MBAR + MCFSIM_QDR); + QSPIDEBUG("%x ",*cp); + cp++; + }QSPIDEBUG("\n"); + } + if (word) + n <<= 1; + + total += n; + } + + return(total); +} + +/** + * qspi_internal_write + * write an array of data to the queued SPI bus + * like qspi_internal_read, hardware configuration + * is done at the beginning of this routine. + * This function is not thread safe, qspi_mutex_up/down should be used. + * @param dev device node containing transfer mode information + * @buffer kernel space array containing the data to send + * @length amount of data to transfer should not be >sizeof(buffer) + * @off unused + * @qcr_cs slave select bitmap to use, ie. 3 would toggle SS0 and 1 + * @return 0 on success + */ +ssize_t qspi_internal_write(qspi_dev *dev, const char *buffer, size_t length, + loff_t *off,int qcr_cs){ + int i = 0; + int total = 0; + int z; + int max_trans; + unsigned char bits; + unsigned char word = 0; + //unsigned long flag; + + + QMR = QMR_MSTR | + (dev->dohie << 14) | + (dev->bits << 10) | + (dev->cpol << 9) | + (dev->cpha << 8) | + (dev->baud); + + QDLYR = (dev->qcd << 8) | dev->dtl; + + bits = (QMR >> 10) % 0x10; + if (bits == 0 || bits > 0x08) + word = 1; /* 9 to 16 bit transfers */ + + + /* next line was memcpy_fromfs() */ + + QSPIDEBUG("length = %x \n",length); + //printk("data to write is %x %x %x %X \n",dbuf[0],dbuf[1],dbuf[2],dbuf[3]); + + if (dev->odd_mod) + z = QCR_SETUP8; + else + z = QCR_SETUP; + + if (dev->dsp_mod) + max_trans = 15; + else + max_trans = 16; + + while (i < length) { + int x; + int n; + + QAR = TX_RAM_START; /* address: first QTR */ + if (word) { + for (n = 0; n < max_trans; ) { + /* in odd mode last byte will be transfered in byte mode */ + if (dev->odd_mod && (i + 1 == length)) { + QDR = buffer[i]; /* tx data: QDR write */ + QSPIDEBUG("0x%X ", dbuf[i]); + n++; + i++; + break; + } + else { + QDR = (buffer[i] << 8) + buffer[i+1]; /* tx data: QDR write */ + QSPIDEBUG("0x%X 0x%X ", dbuf[i], dbuf[i+1]); + n++; + i += 2; + if (i >= length) + break; + } + } + } else { + /* 8bit transfers */ + QSPIDEBUG("8 bit write : "); + for (n = 0; n < max_trans; ) { + QSPIDEBUG("%x ",buffer[i]); + QDR = buffer[i]; /* tx data: QTR write */ + n++; + i++; + if (i == length) + break; + } + QSPIDEBUG("\n"); + } + + QAR = COMMAND_RAM_START; /* address: first QCR */ + for (x = 0; x < n; x++) { + /* QCR write */ + if (dev->qcr_cont) { + if (x == n-1 && i == length) + if ((i % 2)!= 0) + QDR = z | qcr_cs; /* last transfer and odd number of chars */ + else + QDR = QCR_SETUP | qcr_cs; /* last transfer */ + else + QDR = QCR_CONT | QCR_SETUP | qcr_cs; + } else { + if (x == n - 1 && i == length) + QDR = z | qcr_cs; /* last transfer */ + else + QDR = QCR_SETUP | qcr_cs; + } + } + + QWR = QWR_CSIV | ((n - 1) << 8); /* QWR[ENDQP] = n << 8 */ + + /* check if we are using polling mode. Polling increases + * performance for small data transfers but is dangerous + * if we stay too long here, locking other tasks!! + */ + if (dev->poll_mod) { + QIR = QIR_SETUP_POLL; + QDLYR |= QDLYR_SPE; + + while ((QIR & QIR_SPIF) != QIR_SPIF) + ; + QIR = QIR | QIR_SPIF; + } else { + QIR = QIR_SETUP; + // save_flags(flag); cli(); // added according to gerg@snapgear.com - handled by mutex? + QDLYR |= QDLYR_SPE; + +// interruptible_sleep_on(&wqueue); + sleep_on(&wqueue); // changed richard@opentcp.org + + //restore_flags(flag); // added according to gerg@snapgear.com + } + + + if (word) + n <<= 1; + + total += n; + } + + return(total); + } + +/** + * qspi_control + * Set configuration bits in the device structure or create an array + * of data to transfer during the next tranceive operation. + * This function does not actually interface with any hardware, it is used + * only for modifying the device structure. From kernel space this could + * be done more efficiently by directly modifying the structure. + * This function is not thread safe, qspi_mutex_up/down should be used. + * @param dev device node containing transfer mode information + * @param cmd IOCTL command see mcf_qspi.h + * @param arg IOCTL arg + * @return 0 on success + */ +int qspi_control(qspi_dev *dev, unsigned int cmd, unsigned long arg){ + int ret = 0; + struct qspi_read_data *read_data; + + + switch (cmd) { + /* Set QMR[DOHIE] (high-z Dout between transfers) */ + case QSPIIOCS_DOUT_HIZ: + dev->dohie = (arg ? 1 : 0); + break; + + /* Set QMR[BITS] */ + case QSPIIOCS_BITS: + if (((arg > 0) && (arg < 8)) || (arg > 16)) { + ret = -EINVAL; + break; + } + + dev->bits = (u8)arg; + break; + + /* Get QMR[BITS] */ + case QSPIIOCG_BITS: + *((int *)arg) = dev->bits; + break; + + /* Set QMR[CPOL] (QSPI_CLK inactive state) */ + case QSPIIOCS_CPOL: + dev->cpol = (arg ? 1 : 0); + break; + + /* Set QMR[CPHA] (QSPI_CLK phase, 1 = rising edge) */ + case QSPIIOCS_CPHA: + dev->cpha = (arg ? 1 : 0); + break; + + /* Set QMR[BAUD] (QSPI_CLK baud rate divisor) */ + case QSPIIOCS_BAUD: + if (arg > 255) { + ret = -EINVAL; + break; + } + + dev->baud = (u8)arg; + break; + + /* Set QDR[QCD] (QSPI_CS to QSPI_CLK setup) */ + case QSPIIOCS_QCD: + if (arg > 127) { + ret = -EINVAL; + break; + } + + dev->qcd = (u8)arg; + break; + + /* Set QDR[DTL] (QSPI_CLK to QSPI_CS hold) */ + case QSPIIOCS_DTL: + if (arg > 255) { + ret = -EINVAL; + break; + } + + dev->dtl = (u8)arg; + break; + + /* Set QCRn[CONT] (QSPI_CS continuous mode, 1 = remain + * asserted after transfer of 16 data words) */ + case QSPIIOCS_CONT: + dev->qcr_cont = (arg ? 1 : 0); + break; + + /* Set DSP mode, used to limit transfers to 15 bytes for + * 24-bit DSPs */ + case QSPIIOCS_DSP_MOD: + dev->dsp_mod = (arg ? 1 : 0); + break; + + /* If an odd count of bytes is transferred, force the transfer + * of the last byte to byte mode, even if word mode is used */ + case QSPIIOCS_ODD_MOD: + dev->odd_mod = (arg ? 1 : 0); + break; + + /* Set driver to use polling mode, which may increase + * performance for small transfers */ + case QSPIIOCS_POLL_MOD: + dev->poll_mod = (arg ? 1 : 0); + break; + + + /* Kernel space copy function + * Set data buffer to be used as "send data" during reads + * */ + case QSPIIOCS_READDATA: + read_data = (struct qspi_read_data *)arg; + dev->read_data.length = read_data->length; + dev->read_data.buf = read_data->buf; + dev->read_data.loop = read_data->loop; + break; + + + default: + ret = -EINVAL; + break; + + } + +return ret; +} + +/** +* Perform baud rate calculation for QMR register +*@param desired integer setting for desired baud rate +*@returns divider setting for QMR, -1 for invalid settings +*/ +u16 qspi_BAUD(int desired){ + u16 baud = MCF_CLK/(2*desired); + if((baud>QMR_BAUD)||(baud<2)) + return -1;//invalid setting + return baud; +} + +/*------------------------------------------------------------------------------ + * End Kernal function calls + */ + + + +/** + * qspi_interrupt + * hooked at initialization. + * This logs error messages with printk and wakes up a process on + * the waitqueue. + */ +#ifdef LINUX26 +static irqreturn_t qspi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#else +static void qspi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#endif +{ + u16 qir = (QIR & (QIR_WCEF | QIR_ABRT | QIR_SPIF)); + + /* Check write collision and transfer abort flags. Report any + * goofiness. */ + if (qir & QIR_WCEF) + printk(KERN_INFO "%s: WCEF\n", __FILE__); + + if (qir & QIR_ABRT) + printk(KERN_INFO "%s: ABRT\n", __FILE__); + + /* Check for completed transfer. Wake any tasks sleeping on our + * global wait queue. */ + if (qir & QIR_SPIF) + wake_up(&wqueue); + + /* Clear any set flags. */ + QIR |= qir; + +#ifdef LINUX26 +return IRQ_RETVAL(1); +#endif +} + +/** + * qspi_ioctl + * Standard ioctl system call for qspi character devices + * calls qspi_control protected by the qspi mutex. + */ +static int qspi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg){ + struct qspi_dev *dev = filp->private_data; + qspi_read_data *read_data; + int error; + int ret; + int length; + __u8 *kbuffer; + __u8 *ubuffer; + int i; + + QSPIDEBUG("qspi ioctl\n"); + + /* User space copy function + * Set data buffer to be used as "send data" during reads + * */ + if(cmd==QSPIIOCS_READDATA){ + QSPIDEBUG("READDATA set\n"); + read_data = (struct qspi_read_data *)arg; + /* + error = verify_area(VERIFY_READ, read_data, + sizeof(struct qspi_read_data)); + */ + error = access_ok(VERIFY_READ, (void *)arg , + sizeof(struct qspi_read_data)); + + if (!error) { + printk("couldn't read from %lx\n",(unsigned long) read_data); + return error; + } + //store old data buffer location + kbuffer = dev->read_data.buf; + //copy in user structure + copy_from_user(&dev->read_data, read_data,sizeof(struct qspi_read_data)); + //get user data location + ubuffer = dev->read_data.buf; + length = dev->read_data.length; + dev->read_data.buf = kbuffer;//reset kernel pointer + + /*make sure user buffer is <= kbuffer size*/ + if(length>QSPIBSZ) + return(-EINVAL); + /*get user data*/ + copy_from_user(kbuffer, ubuffer,length); + QSPIDEBUG("copied over : "); + for(i=0;iread_data.buf[i]); + QSPIDEBUG("\n"); + return 0; + } + //use qspi_control if we don't have to map anything from user space + down_interruptible(&sem); + ret = qspi_control(dev,cmd,arg); + up(&sem); + return ret; +} + +/** + * qspi_open + * Standard open system call for character qspi devices + * creates a qspi device in private data + */ +static int qspi_open(struct inode *inode, struct file *file){ + + qspi_dev *device = qspi_create_device(); + if(device==NULL) + return(-ENOMEM); + + if ((device->read_data.buf = kmalloc(QSPIBSZ, GFP_KERNEL)) == NULL) { + qspi_destroy_device(device); + return(-ENOMEM); + } + file->private_data = device; + + return(0); +} + + +/** + * qspi_release + * Standard close system call for character qspi devices + * destroys the qspi device in private data + */ +static int qspi_release(struct inode *inode, struct file *file) +{ + qspi_destroy_device(file->private_data); + file->private_data = NULL; + return(0); +} + +/** + * qspi_read + * Standard read system call for character qspi devices + * gets cs number from device minor. + * doesn't implement the offset arguement + * calls qspi_internal_read protected by the qspi mutex + */ +static ssize_t qspi_read(struct file *filep, char *buffer, size_t length, + loff_t *off){ + /* CS for QCR */ + int qcr_cs = (~MINOR(filep->f_dentry->d_inode->i_rdev) << 8) & 0xf00; + int ret; + qspi_dev *dev = filep->private_data; + down_interruptible(&sem); + ret = qspi_internal_read(dev, dbuf, length,off,qcr_cs); + up(&sem); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + memcpy_tofs(buffer, dbuf,length); +#else + copy_to_user(buffer, dbuf,length); +#endif + return ret; + } + +/** + * qspi_write + * Standard write system call for character qspi devices + * gets cs number from device number + * doesn't implement the offset arguement + * calls qspi_internal_write protected by the qspi mutex + */ +static ssize_t qspi_write(struct file *filep, const char *buffer, size_t length, + loff_t *off){ + int ret; + qspi_dev *dev= filep->private_data; + int qcr_cs = (~MINOR(filep->f_dentry->d_inode->i_rdev) << 8) & 0xf00; /* CS for QCR */ + if(length>sizeof(dbuf)) + return -ENOMEM; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + memcpy_fromfs(dbuf, buffer,length); +#else + copy_from_user (dbuf, buffer, length); +#endif + down_interruptible(&sem); + ret = qspi_internal_write(dev,dbuf,length, off,qcr_cs); + up(&sem); + return ret; + } + +/** + * qspi character file operations structure + */ +static struct file_operations Fops = { + owner: THIS_MODULE, + read: qspi_read, + write: qspi_write, + ioctl: qspi_ioctl, + open: qspi_open, + release: qspi_release /* a.k.a. close */ +}; + + +/** + * init + * module initialization function. + * hooks the interrupt and initializes the hardware + */ +static int init(void) +{ + volatile u32 *lp; + volatile u8 *cp; + + /* common init: driver or module: */ + + if (request_irq(MCFQSPI_IRQ_VECTOR, qspi_interrupt, SA_INTERRUPT, "ColdFire QSPI", NULL)) { + printk("QSPI: Unable to attach ColdFire QSPI interrupt " + "vector=%d\n", MCFQSPI_IRQ_VECTOR); + return(-EINVAL); + } + +#if defined(CONFIG_M5249) + cp = (volatile u8 *)(MCF_MBAR + MCFSIM_ICR10); + *cp = 0x8f; /* autovector on, il=3, ip=3 */ + + lp = (volatile u32 *)(MCF_MBAR2 + 0x180); + *lp |= 0x00000800; /* activate qspi_in and qspi_clk */ + + lp = (volatile u32 *)(MCF_MBAR2 + MCFSIM2_GPIOFUNC); + *lp &= 0xdc9FFFFF; /* activate qspi_cs0 .. 3, qspi_dout */ + + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_IMR); + *lp &= 0xFFFbFFFF; /* enable qspi interrupt */ +#elif defined(CONFIG_M5235) + // interrupts mask here + { + volatile unsigned char *icrp; + icrp = (volatile unsigned char *)(MCF_MBAR + MCF5235ICM_INTC0 + MCFINTC0_ICR); + icrp[IRQ_SOURCE] = (( 3/*IL*/ & 0x3 ) << 3 ) | (3 /*IP*/ & 0x3); + } + { + volatile unsigned int *imrl; + imrl = (volatile unsigned int *)(MCF_MBAR + MCF5235ICM_INTC0 + MCF5235INTC_IMRL); + *imrl &= ~(1 << IRQ_SOURCE); + } + // GPIO here + { + volatile unsigned char *parp; + parp = (volatile unsigned char *)(MCF_MBAR + 0x10004A); + *parp = 0xFF; + } +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)|| defined(CONFIG_M528x)) + cp = (volatile u8 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + + MCFINT_QSPI); + + *cp = (5 << 3) + 3; /* level 5, priority 3 */ + + +#ifdef CONFIG_SOM5282EM + cp = (volatile u8 *) (MCF_IPSBAR + MCF5282_GPIO_PQSPAR); + *cp = 0x3f; /* activate din, dout, clk and cs[0..2] // RTC has reverse polarity */ +#else + cp = (volatile u8 *) (MCF_IPSBAR + MCF5282_GPIO_PQSPAR); + *cp = 0x7f; /* activate din, dout, clk and cs[0..3] */ +#endif + lp = (volatile u32 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL); + *lp &= ~(1 + (1 << MCFINT_QSPI)); /* enable qspi interrupt */ +#else + /* set our IPL */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_ICR4); + *lp = (*lp & 0x07777777) | 0xd0000000; + + /* 1) CS pin setup 17.2.x + * Dout, clk, cs0 always enabled. Din, cs[3:1] must be enabled. + * CS1: PACNT[23:22] = 10 + * CS1: PBCNT[23:22] = 10 ? + * CS2: PDCNT[05:04] = 11 + * CS3: PACNT[15:14] = 01 + */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_PACNT); + *lp = (*lp & 0xFF3F3FFF) | 0x00804000; /* 17.2.1 QSPI CS1 & CS3 */ + lp = (volatile u32 *)(MCF_MBAR + MCFSIM_PDCNT); + *lp = (*lp & 0xFFFFFFCF) | 0x00000030; /* QSPI_CS2 */ +#endif + + /* + * These values have to be setup according to the applications + * using the qspi driver. Maybe some #defines at the beginning + * would be more appropriate. Especially the transfer size + * and speed settings + */ + QMR = 0xA1A2; // default mode setup: 8 bits, baud, 160kHz clk. +// QMR = 0x81A2; // default mode setup: 16 bits, baud, 160kHz clk. + QDLYR = 0x0202; // default start & end delays + + init_waitqueue_head(&wqueue); /* was init_waitqueue() --Ron */ + +#if defined(CONFIG_M5249) + printk("MCF5249 QSPI driver ok\n"); +#elif defined(CONFIG_M5235) + printk("MCF5235 QSPI driver ok\n"); +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280)|| defined(CONFIG_M528x)) + printk("MCF5282 QSPI driver ok\n"); +#else + printk("MCF5272 QSPI driver ok\n"); +#endif + + return(0); +} + + + +/* + * And the bus type. + */ + /* +struct bus_type qspi_bus_type = { + .name = "mcfqspi", + .match = qspi_match, +}; +*/ + +/* init for qspi module */ +int __init qspi_init(void) /* the __init added by ron */ +{ + int ret; +#ifdef DEVFS + if ((ret = devfs_register_chrdev(QSPI_MAJOR, DEVICE_NAME, &Fops) < 0)) { + printk ("%s device failed with %d\n", + "Sorry, registering the character", ret); + return(ret); + } +#else + +/*register mcf_qspi driver as a bus*/ +//if(ret = bus_register(&qspi_bus_type)) +// return ret; + + if ((ret = register_chrdev(QSPI_MAJOR, DEVICE_NAME, &Fops) < 0)) { + printk ("%s device failed with %d\n", + "Sorry, registering the character", ret); + return(ret); + } +#endif + + + printk ("QSPI device driver installed OK\n"); + return(init()); +} + +/* Cleanup - undid whatever init_module did */ +void __exit qspi_exit(void) /* the __exit added by ron */ +{ + int ret; + + free_irq(MCFQSPI_IRQ_VECTOR, NULL); + +#if defined(CONFIG_M5249) + /* autovector on, il=0, ip=0 */ + *(volatile u8 *)(MCF_MBAR + MCFSIM_ICR10) = 0x80; + /* disable qspi interrupt */ + *(volatile u32 *)(MCF_MBAR + MCFSIM_IMR) |= 0x00040000; +#elif defined(CONFIG_M5235) + { + volatile unsigned char *icrp; + icrp = (volatile unsigned char *)(MCF_MBAR + MCF5235ICM_INTC0 + MCFINTC0_ICR); + icrp[IRQ_SOURCE] = 0; + } + // GPIO here + { + volatile unsigned char *parp; + parp = (volatile unsigned char *)(MCF_MBAR + 0x10004A); + *parp = 0x00; + } +#elif (defined(CONFIG_M5282) || defined(CONFIG_M5280) || defined(CONFIG_M528x)) + /* interrupt level 0, priority 0 */ + *(volatile u8 *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_QSPI) = 0; + /* disable qspi interrupt */ + *(volatile u32 *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL) + |= (1 << MCFINT_QSPI); +#else + /* zero our IPL */ + *((volatile u32 *)(MCF_MBAR + MCFSIM_ICR4)) = 0x80000000; +#endif + + /* Unregister the device */ +//bus_unregister(&qspi_bus_type); + +#ifdef DEVFS + if ((ret = devfs_unregister_chrdev(QSPI_MAJOR, DEVICE_NAME)) < 0) + printk("Error in unregister_chrdev: %d\n", ret); +} +#else + if ((ret = unregister_chrdev(QSPI_MAJOR, DEVICE_NAME)) < 0) + printk("Error in unregister_chrdev: %d\n", ret); +} +#endif + + + +module_init(qspi_init); /* added by ron so driver can compile directly into kernel */ +module_exit(qspi_exit); /* added by ron so driver can compile directly into kernel */ + + + + diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index f9b1719b..fa8188ef 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -39,6 +39,7 @@ config USB_ARCH_HAS_EHCI boolean default y if PPC_83xx default y if SOC_AU1200 + default y if ARCH_MOXART default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9801d08e..cec41f46 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -6,6 +6,11 @@ #include #include "hcd.h" +#ifdef CONFIG_LEDMAN +#include +static int ledcnt = 0; +#endif + #define to_urb(d) container_of(d, struct urb, kref) static void urb_destroy(struct kref *kref) @@ -373,6 +378,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->interval = temp; } +#ifdef CONFIG_LEDMAN + if (ledcnt++ % 10 == 0) + ledman_cmd(LEDMAN_CMD_SET, LEDMAN_USB1_TX); +#endif + return usb_hcd_submit_urb (urb, mem_flags); } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 9030994a..0b9984e1 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -304,7 +304,9 @@ ehci_shutdown (struct usb_hcd *hcd) (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ +#ifndef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 writel (0, &ehci->regs->configured_flag); +#endif } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -378,7 +380,9 @@ static void ehci_stop (struct usb_hcd *hcd) spin_unlock_irq(&ehci->lock); /* let companion controllers work when we aren't */ +#ifndef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 writel (0, &ehci->regs->configured_flag); +#endif remove_debug_files (ehci); @@ -536,7 +540,9 @@ static int ehci_run (struct usb_hcd *hcd) * and there's no companion controller unless maybe for USB OTG.) */ hcd->state = HC_STATE_RUNNING; +#ifndef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 writel (FLAG_CF, &ehci->regs->configured_flag); +#endif readl (&ehci->regs->command); /* unblock posted writes */ temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); @@ -646,7 +652,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ehci_err (ehci, "fatal error\n"); dead: ehci_reset (ehci); +#ifndef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 writel (0, &ehci->regs->configured_flag); +#endif /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ @@ -895,6 +903,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif +#ifdef CONFIG_ARCH_MOXART +#include "ehci-moxaart.c" +#define PLATFORM_DRIVER ehci_hcd_moxaart_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" #endif diff --git a/drivers/usb/host/ehci-moxaart.c b/drivers/usb/host/ehci-moxaart.c new file mode 100644 index 00000000..710f3731 --- /dev/null +++ b/drivers/usb/host/ehci-moxaart.c @@ -0,0 +1,237 @@ +/* + * EHCI HCD (Host Controller Driver) for USB. + * + * History : + * Date Author Comment + * 08-03-2007 Victor Yu. Create it. + */ + +#include +#include +#include + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void moxaart_start_ehc(struct platform_device *dev) +{ + pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n"); + + /* write HW defaults again in case Yamon cleared them */ + if (au_readl(USB_HOST_CONFIG) == 0) { + au_writel(0x00d02000, USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + } + /* enable host controller */ + au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), + USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + + pr_debug(__FILE__ ": Clock to USB host has been enabled\n"); +} + +static void moxaart_stop_ehc(struct platform_device *dev) +{ + pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n"); + + /* Disable mem */ + au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + udelay(1000); + /* Disable clock */ + au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG), + USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); +} + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_ehci_moxaart_probe - initialize Au1xxx-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + */ +int usb_ehci_moxaart_probe(const struct hc_driver *driver, + struct usb_hcd **hcd_out, struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + + moxaart_start_ehc(dev); + + if (dev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ"); + retval = -ENOMEM; + } + hcd = usb_create_hcd(driver, &dev->dev, "MoxaART"); + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = dev->resource[0].start; + hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed"); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_debug("ioremap failed"); + retval = -ENOMEM; + goto err2; + } + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl(&ehci->caps->hcs_params); + + /* ehci_hcd_init(hcd_to_ehci(hcd)); */ + + retval = + usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED); + if (retval == 0) + return retval; + + au1xxx_stop_ehc(dev); + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return retval; +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_ehci_moxaart_remove(struct usb_hcd *hcd, struct platform_device *dev) +{ + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + moxaart_stop_ehc(dev); +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ehci_moxaart_hc_driver = { + .description = hcd_name, + .product_desc = "MoxaART EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_init, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#ifdef CONFIG_PM + .hub_suspend = ehci_hub_suspend, + .hub_resume = ehci_hub_resume, +#endif +}; + +/*-------------------------------------------------------------------------*/ + +static int ehci_hcd_moxaart_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd = NULL; + int ret; + + pr_debug("In ehci_hcd_moxaart_drv_probe\n"); + + if (usb_disabled()) + return -ENODEV; + + ret = usb_ehci_moxaart_probe(&ehci_moxaart_hc_driver, &hcd, pdev); + return ret; +} + +static int ehci_hcd_moxaart_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_ehci_moxaart_remove(hcd, pdev); + return 0; +} + + /*TBD*/ +/*static int ehci_hcd_moxaart_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +static int ehci_hcd_moxaart_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +*/ +MODULE_ALIAS("moxaart-ehci"); +static struct platform_driver ehci_hcd_moxaart_driver = { + .probe = ehci_hcd_moxaart_drv_probe, + .remove = ehci_hcd_moxaart_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + /*.suspend = ehci_hcd_moxaart_drv_suspend, */ + /*.resume = ehci_hcd_moxaart_drv_resume, */ + .driver = { + .name = "moxaart-ehci", + .bus = &platform_bus_type + } +}; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bbc3082a..494404c1 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -236,6 +236,106 @@ struct ehci_regs { /* ASYNCLISTADDR: offset 0x18 */ u32 async_next; /* address of next async queue head */ +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 + /* not used: offset 0x1C */ + u32 reserved; + + /* PORTSC: offset 0x20 */ + u32 port_status [1]; /* just one port */ +/* 31:23 reserved */ +#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ +#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ +#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ +/* 19:16 for port testing */ +#define PORT_LED_OFF (0<<14) +#define PORT_LED_AMBER (1<<14) +#define PORT_LED_GREEN (2<<14) +#define PORT_LED_MASK (3<<14) +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */ +/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ +/* 9 reserved */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_OCC (1<<5) /* over current change */ +#define PORT_OC (1<<4) /* over current active */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ + + /* EOF time & asynchronous schedule sleep timer register: offset 0x24 */ + u32 eof_time; +#define U_SUSP_N (1<<6) /* transceiver suspend mode */ + +#define EOF2_TIME_MASK (3<<4) +#define EOF2_TIME_2 (0<<4) /* high-speed E0F2 time 2 clocks */ +#define EOF2_TIME_4 (1<<4) /* high-speed EOF2 time 4 clocks */ +#define EOF2_TIME_8 (2<<4) /* high-speed EOF2 time 8 clocks */ +#define EOF2_TIME_16 (3<<4) /* high-speed EOF2 time 16 clocks */ +#define EOF2_TIME_20 (0<<4) /* full-speed EOF2 time 20 clocks */ +#define EOF2_TIME_40 (1<<4) /* full-speed EOF2 time 40 clocks */ +#define EOF2_TIME_80 (2<<4) /* full-speed EOF2 time 80 clocks */ +#define EOF2_TIME_160 (3<<4) /* full-speed EOF2 time 160 clocks */ +#define EOF2_TIME_40L (0<<4) /* low-speed EOF2 time 40 clocks */ +#define EOF2_TIME_80L (1<<4) /* low-speed EOF2 time 80 clocks */ +#define EOF2_TIME_160L (2<<4) /* low-speed EOF2 time 160 clocks */ +#define EOF2_TIME_320L (3<<4) /* low-speed EOF2 time 320 clocks */ + + /* 0x28 - 0x2C : reserved */ + u32 reserved2[2]; + + /* bus monitor control/status: offset 0x30 */ + u32 bus_mon; +#define HOST_SPEED_MASK (3<<9) +#define HOST_SPEED_HS (2<<9) /* High speed */ +#define HOST_SPEED_FS (0<<9) /* full speed */ +#define HOST_SPEED_LS (1<<9) /* low speed */ +#define VBUS_VLD (0<<8) /* VBUS valid */ +#define VBUS_INVLD (1<<8) /* VBUS invalid */ +#define FORCE_HIGH_SPEED (1<<6) +#define FORCE_FULL_SPEED (1<<7) +#define VBUS_ON (0<<4) /* VBUS on */ +#define VBUS_OFF (1<<4) /* VBUS off */ +#define INT_ACT_LOW (0<<3) /* interrupt active low */ +#define INT_ACT_HIGH (1<<3) /* interrupt active high */ + + /* bus monitor interrupt status: offset 0x34 */ + u32 bus_mon_int; + + /* bus monitor interrrupt enable: offset 0x38 */ + u32 bus_mon_int_enable; + + /* 0x3C reserved */ + u32 reserved3; + + /* test register: offset 0x40 */ + u32 test; + + /* vendor specific IO control: offset 0x44 */ + u32 vendor_io; + + /* vendor specific status: offset 0x48 */ + u32 vendor_status; + + /* 0x4c - 0x5c reserved */ + u32 reserved4[5]; + + /* DMA controller parameter setting 1: offset 0x60 */ + u32 dma_cntl1; + + /* DMA controller parameter setting 2: offset 0x64 */ + u32 dma_cntl2; + + /* 0x68 - 0x6c reserved */ + u32 reserved5[2]; + + /* PHY control register */ + u32 phy_ctrl; +#define PHY_RESET (1<<15) +#else // CONFIG_ARCH_MOXACPU u32 reserved [9]; /* CONFIGFLAG: offset 0x40 */ @@ -267,6 +367,7 @@ struct ehci_regs { #define PORT_PE (1<<2) /* port enable */ #define PORT_CSC (1<<1) /* connect status change */ #define PORT_CONNECT (1<<0) /* device connected */ +#endif // CONFIG_ARCH_MOXART #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) } __attribute__ ((packed)); @@ -618,6 +719,17 @@ struct ehci_fstn { static inline unsigned int ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) { +#ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 07-24-2007 + switch ( readl(&ehci->regs->bus_mon) & HOST_SPEED_MASK ) { + case HOST_SPEED_FS : + return 0; + case HOST_SPEED_LS : + return (1 << USB_PORT_FEAT_LOWSPEED); + case HOST_SPEED_HS : + default : + return (1 << USB_PORT_FEAT_HIGHSPEED); + } +#else if (ehci_is_TDI(ehci)) { switch ((portsc>>26)&3) { case 0: @@ -629,6 +741,7 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) return (1< describes the available parameters. +config FB_DM270 + tristate "TI TMS320DM270 OSD framebuffer support" + depends on FB && ARM && MACH_DM270 + ---help--- + Frame buffer driver for TI TMS320DM270 on-chip OSD Controller. + See for information on framebuffer + devices. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called vfb. If you want to compile it as a module, + say M here and read . + + If unsure, say N. + +config FB_S1D13XXX + tristate "Epson S1D13XXX framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Support for S1D13XXX framebuffer device family (currently only + working with S1D13806). Product specs at + + config FB_MBX tristate "2700G LCD framebuffer support" depends on FB && ARCH_PXA diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a6980e9a..6b600bae 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o +obj-$(CONFIG_FB_M532x) += m532xfb.o obj-$(CONFIG_FB_MATROX) += matrox/ obj-$(CONFIG_FB_RIVA) += riva/ vgastate.o @@ -86,6 +87,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_DM270) += dm270fb.o obj-$(CONFIG_FB_W100) += w100fb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o obj-$(CONFIG_FB_AU1200) += au1200fb.o diff --git a/drivers/video/dm270fb.c b/drivers/video/dm270fb.c new file mode 100644 index 00000000..2b4fefc7 --- /dev/null +++ b/drivers/video/dm270fb.c @@ -0,0 +1,1548 @@ +/* + * drivers/video/dm270fb.c + * + * Copyright (C) 2004 Chee Tim Loh + * + * Based on drivers/video/cyber2000fb.c + * Copyright (C) 1998-2002 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. + * + * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device + * + * Based on cyberfb.c. + * + * Note that we now use the new fbcon fix, var and cmap scheme. We do + * still have to check which console is the currently displayed one + * however, especially for the colourmap stuff. + * + * We also use the new hotplug PCI subsystem. I'm not sure if there + * are any such cards, but I'm erring on the side of caution. We don't + * want to go pop just because someone does have one. + * + * Note that this doesn't work fully in the case of multiple CyberPro + * cards with grabbers. We currently can only attach to the first + * CyberPro card found. + * + * When we're in truecolour mode, we power down the LUT RAM as a power + * saving feature. Also, when we enter any of the powersaving modes + * (except soft blanking) we power down the RAMDACs. This saves about + * 1W, which is roughly 8% of the power consumption of a NetWinder + * (which, incidentally, is about the same saving as a 2.5in hard disk + * entering standby mode.) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dm270fb.h" + +/* -------------------- Global Variables ----------------------------------- */ + +static struct fb_info dm270fbinfo[DM270FB_NR_FB]; +static char *dm270fb_options __initdata = NULL; + +static struct dm270fb_cfg dm270fb_bootcfg = { + .noaccel = 1, + .nopan = 1, + .nowrap = 1, + .nohwcursor = 1, + .cmap_inverse = 0, + .cmap_static = 1, + .fontname = {'\0'}, + .disp_type = DM270FB_DEFAULT_DISPTYPE, /* composite */ + .vidout_std = DM270FB_DEFAULT_VIDFMT, /* NTSC */ +}; + +static struct fb_var_screeninfo dm270fb_bootvar = { + .xres = DM270FB_DEFAULT_XRES, /* 640 */ + .yres = DM270FB_DEFAULT_YRES, /* 480 */ + .xres_virtual = DM270FB_DEFAULT_XRES, + .yres_virtual = DM270FB_DEFAULT_YRES, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = DM270FB_DEFAULT_BPP, /* 8 */ + .grayscale = 0, + /* for bpp <= 8, length of red = length of green = length of blue = bpp */ + .red = {0, DM270FB_DEFAULT_BPP, 0}, + .green = {0, DM270FB_DEFAULT_BPP, 0}, + .blue = {0, DM270FB_DEFAULT_BPP, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = DM270FB_DEFAULT_PIXCLOCK, /* 0 */ + .left_margin = DM270FB_DEFAULT_LEFT_MARGIN, /* 0 */ + .right_margin = DM270FB_DEFAULT_RIGHT_MARGIN, /* 0 */ + .upper_margin = DM270FB_DEFAULT_UPPER_MARGIN, /* 0 */ + .lower_margin = DM270FB_DEFAULT_LOWER_MARGIN, /* 0 */ + .hsync_len = DM270FB_DEFAULT_HSYNC_LEN, /* 0 */ + .vsync_len = DM270FB_DEFAULT_VSYNC_LEN, /* 0 */ + .sync = DM270FB_DEFAULT_SYNC, /* csync */ + .vmode = DM270FB_DEFAULT_VMODE, /* interlaced */ + .rotate = 0, +}; + +/* -------------------- ROM Color Lookup Table ----------------------------- */ + +static u16 dm270fb_romclut_red[] = { + 0x0000, 0xa400, 0x0000, 0x8600, 0x0000, 0x9e00, 0x0000, 0xc000, + 0xb900, 0x9900, 0xfb00, 0x0800, 0x1000, 0x1800, 0x2100, 0x2900, + 0x3100, 0x4a00, 0x5a00, 0x7300, 0x7b00, 0x9400, 0xa500, 0xbd00, + 0x4c00, 0x7f00, 0x7700, 0x6700, 0xa500, 0x8d00, 0x8400, 0x8600, + 0x8800, 0xae00, 0xa600, 0xa800, 0xc800, 0xf200, 0xae00, 0x8f00, + 0xec00, 0xa600, 0x8d00, 0xdd00, 0x6400, 0xb700, 0xd700, 0x6700, + 0xc500, 0xce00, 0xfb00, 0x5200, 0xa800, 0xff00, 0xca00, 0x7800, + 0x7600, 0xd700, 0xe800, 0xff00, 0xff00, 0x6000, 0x5800, 0xff00, + 0xff00, 0x6600, 0x2400, 0x6000, 0x5800, 0x3c00, 0x9800, 0x5e00, + 0x5600, 0x9400, 0x8c00, 0x7b00, 0x3500, 0x6200, 0xea00, 0x4700, + 0x8900, 0xdf00, 0x6800, 0xbf00, 0x9d00, 0xe400, 0xaf00, 0xdc00, + 0xe500, 0xe800, 0xd900, 0xe100, 0xe900, 0xda00, 0xc000, 0x4f00, + 0xef00, 0xac00, 0xe200, 0xeb00, 0xe300, 0xf500, 0xff00, 0xe600, + 0x8000, 0x8900, 0x7600, 0x7600, 0x6300, 0x5100, 0x4500, 0x3d00, + 0x3c00, 0x2a00, 0x4500, 0x0800, 0x1600, 0x0e00, 0x3600, 0x6d00, + 0x1600, 0x0600, 0x2600, 0x0d00, 0x1700, 0x1f00, 0x1700, 0x0f00, + 0x1100, 0x0100, 0x0200, 0x0000, 0x0000, 0x0500, 0x8100, 0x3f00, + 0x2600, 0x1e00, 0x1500, 0x4c00, 0x2e00, 0x2900, 0x8f00, 0x0500, + 0x6800, 0x5800, 0x1400, 0x0000, 0x0000, 0xa200, 0x6d00, 0x0000, + 0x7e00, 0x7400, 0x6200, 0x6000, 0x0000, 0xaf00, 0x8e00, 0x4c00, + 0x2b00, 0x1200, 0x0000, 0x0000, 0xe400, 0xc800, 0xb400, 0x9c00, + 0x8b00, 0x1e00, 0x7000, 0x5100, 0x6000, 0x7600, 0x6500, 0x5d00, + 0x3f00, 0x4400, 0x5800, 0x0000, 0x2500, 0x5700, 0x5500, 0x4400, + 0x3600, 0x1200, 0x9300, 0x8300, 0x7200, 0x6200, 0x2800, 0x1a00, + 0x0d00, 0x7400, 0x3200, 0x0600, 0x0000, 0x0000, 0x0000, 0xa700, + 0x4400, 0x3c00, 0x2300, 0x2800, 0x2a00, 0xda00, 0x7700, 0x3900, + 0x4300, 0x1e00, 0x3b00, 0x3200, 0x2a00, 0x0000, 0x0000, 0xa900, + 0x8800, 0x6f00, 0x2d00, 0x2500, 0x0600, 0x0100, 0x5600, 0x4600, + 0x4500, 0xac00, 0x9b00, 0x6a00, 0x6200, 0x5100, 0x5900, 0x4900, + 0x4100, 0x6a00, 0x6200, 0x2000, 0x4800, 0x1700, 0x0f00, 0x4c00, + 0x2300, 0x8a00, 0x5e00, 0x6700, 0x8a00, 0x0000, 0xff00, 0xa000, + 0x8000, 0xfe00, 0x0000, 0xff00, 0x0000, 0xff00, 0x0000, 0xff00, +}; +static u16 dm270fb_romclut_green[] = { + 0x0000, 0x0000, 0x9a00, 0x8d00, 0x0000, 0x0000, 0x8d00, 0xc000, + 0xe000, 0xca00, 0xfb00, 0x0800, 0x1000, 0x1800, 0x2100, 0x2900, + 0x3100, 0x4a00, 0x5a00, 0x7300, 0x7b00, 0x9400, 0xa500, 0xbd00, + 0x4000, 0x6900, 0x6100, 0x5000, 0x7800, 0x6000, 0x5700, 0x4d00, + 0x4500, 0x5400, 0x4c00, 0x4200, 0x4100, 0x0000, 0x3000, 0x0700, + 0x0a00, 0x4c00, 0x3300, 0x1d00, 0x0a00, 0x0c00, 0x0b00, 0x0100, + 0x7500, 0x2f00, 0x2400, 0x0200, 0x2100, 0x1400, 0x6500, 0x1300, + 0x1c00, 0x5c00, 0x4a00, 0x2e00, 0x2400, 0x1e00, 0x1400, 0x3800, + 0x4000, 0x5b00, 0x1900, 0x4d00, 0x4500, 0x3400, 0x7b00, 0x5600, + 0x4e00, 0x8200, 0x7b00, 0x6900, 0x2d00, 0x4f00, 0xd100, 0x3d00, + 0x8000, 0xcf00, 0x5f00, 0xb100, 0x8d00, 0xc400, 0xa000, 0xbc00, + 0xc000, 0xdb00, 0xca00, 0xd200, 0xd800, 0xc600, 0xaf00, 0x4800, + 0xec00, 0xa500, 0xcc00, 0xd100, 0xc900, 0xd700, 0xe300, 0xe200, + 0xd600, 0xd500, 0xd900, 0xd800, 0xd100, 0xc800, 0xcc00, 0xc400, + 0xcc00, 0xc600, 0x9900, 0x3700, 0xbf00, 0xb700, 0x7e00, 0xc100, + 0xbe00, 0xab00, 0x3300, 0x4b00, 0x8100, 0xba00, 0xb200, 0x7900, + 0xa000, 0x2600, 0x8500, 0x2f00, 0x6800, 0x4000, 0x8d00, 0x4b00, + 0x3200, 0x2a00, 0x2100, 0x6400, 0xa800, 0xba00, 0xc700, 0x9f00, + 0xb500, 0xa500, 0x8d00, 0x8d00, 0x7d00, 0xce00, 0xa500, 0x7300, + 0xb600, 0xb500, 0xa600, 0xac00, 0x7a00, 0xc600, 0xa500, 0x6300, + 0x4200, 0x2900, 0x6200, 0x6b00, 0xef00, 0xdd00, 0xd400, 0xbd00, + 0xab00, 0x2900, 0x9b00, 0x7100, 0x8b00, 0xab00, 0x9c00, 0x9200, + 0x6a00, 0x7b00, 0xa400, 0x7100, 0x7100, 0x8300, 0x8a00, 0x7800, + 0x6200, 0x6900, 0xb300, 0xa300, 0x9200, 0x8200, 0x4800, 0x4e00, + 0x5800, 0x8b00, 0x4900, 0x4500, 0x4e00, 0x3500, 0x3e00, 0xbb00, + 0x5800, 0x5000, 0x3700, 0x4700, 0x5f00, 0xe500, 0x8200, 0x5800, + 0x5800, 0x2700, 0x5000, 0x4800, 0x4000, 0x1d00, 0x1d00, 0xb400, + 0x9300, 0x7a00, 0x3800, 0x3000, 0x2400, 0x1400, 0x6100, 0x4f00, + 0x4d00, 0xac00, 0x9a00, 0x6a00, 0x6200, 0x5100, 0x5800, 0x4900, + 0x4100, 0x6900, 0x6100, 0x2000, 0x4700, 0x1600, 0x0f00, 0x3f00, + 0x1600, 0x6600, 0x4800, 0x4f00, 0x6600, 0x0000, 0xfb00, 0x9e00, + 0x8000, 0x0b00, 0xff00, 0xf900, 0x0600, 0x0000, 0xf400, 0xff00, +}; +static u16 dm270fb_romclut_blue[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xd700, 0xb900, 0x9d00, 0xc000, + 0xb300, 0xff00, 0xfb00, 0x0800, 0x1000, 0x1800, 0x2100, 0x2900, + 0x3100, 0x4a00, 0x5a00, 0x7300, 0x7b00, 0x9400, 0xa500, 0xbd00, + 0x4000, 0x6700, 0x5f00, 0x4e00, 0x7300, 0x5b00, 0x5200, 0x4800, + 0x3e00, 0x4a00, 0x4200, 0x3900, 0x3200, 0x0000, 0x1600, 0x0000, + 0x0000, 0x3500, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x6000, 0x0300, 0x0000, 0x0000, 0x0000, 0x0000, 0x3d00, 0x0000, + 0x0000, 0x2400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0a00, + 0x0200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0900, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0300, + 0x1d00, 0x3800, 0x1100, 0x1f00, 0x0c00, 0x0600, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1c00, 0x0000, 0x0000, 0x0000, 0x1c00, 0x5300, + 0x0000, 0x0000, 0x2500, 0x0400, 0x0700, 0x0800, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0a00, 0x8d00, 0x4b00, + 0x3200, 0x2a00, 0x2300, 0x7400, 0xff00, 0xff00, 0xf800, 0xff00, + 0xff00, 0xf700, 0xff00, 0xff00, 0xff00, 0xff00, 0xe600, 0xff00, + 0xf500, 0xff00, 0xf500, 0xff00, 0xff00, 0xe400, 0xc300, 0x8100, + 0x6000, 0x4700, 0xff00, 0xff00, 0xfd00, 0xfe00, 0xff00, 0xec00, + 0xdd00, 0x3700, 0xdb00, 0xa300, 0xcb00, 0xfb00, 0xeb00, 0xe200, + 0xaa00, 0xca00, 0xff00, 0xff00, 0xef00, 0xd000, 0xe800, 0xd900, + 0xaf00, 0xff00, 0xf200, 0xe200, 0xd100, 0xc100, 0x8700, 0xbd00, + 0xe500, 0xb900, 0x7700, 0xd200, 0xff00, 0xc200, 0xe600, 0xea00, + 0x8700, 0x7f00, 0x6600, 0x9400, 0xdb00, 0xff00, 0xa100, 0xa500, + 0x9500, 0x4600, 0x8d00, 0x8500, 0x7d00, 0x7900, 0x9700, 0xd300, + 0xb200, 0x9900, 0x5700, 0x4f00, 0x9000, 0x6200, 0x8d00, 0x7e00, + 0x9900, 0xba00, 0xab00, 0x7800, 0x7000, 0x5f00, 0x6900, 0x5700, + 0x4f00, 0x8500, 0x7d00, 0x2e00, 0x7300, 0x2700, 0x1d00, 0x4d00, + 0x2400, 0x8000, 0x5300, 0x5b00, 0x7300, 0x0000, 0xe700, 0xa700, + 0x8000, 0x0000, 0x0000, 0x0000, 0xfe00, 0xff00, 0xff00, 0xff00, +}; + +static struct fb_cmap dm270fb_romclut_cmap = { + .start = 0, + .len = 256, + .red = dm270fb_romclut_red, + .green = dm270fb_romclut_green, + .blue = dm270fb_romclut_blue, + .transp = NULL, +}; + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Initialise the DM270 hardware + */ +static void __init +dm270fb_init_hw(struct fb_info *fbinfo) +{ + struct dm270fb_par *dm270fbpar = (struct dm270fb_par *)fbinfo->par; + unsigned int bmpwin_addr; + unsigned int osdmode; + unsigned int vid01 = 0; + unsigned int vid02 = 0; + unsigned int basepx = 0; + unsigned int basepy = 0; + int ii; + + if (!dm270fbpar->cfg.noinit) { + /* Disable VENC & DAC */ + outw(0, DM270_VENC_VID01); + + /* Disable clock to OSD, VENC & DAC. */ + outw((inw(DM270_CLKC_MOD1) & + ~(DM270_CLKC_MOD1_COSD | DM270_CLKC_MOD1_CVENC | + DM270_CLKC_MOD1_CDAC)), + DM270_CLKC_MOD1); + + /* Select MXI as VENC clock source, CLK_VENC as OSD clock source */ + outw((inw(DM270_CLKC_CLKC) & + ~(DM270_CLKC_CLKC_CENS0 | DM270_CLKC_CLKC_CENS1 | + DM270_CLKC_CLKC_COSDS | DM270_CLKC_CLKC_CENIV)), + DM270_CLKC_CLKC); + + /* Enable clock to OSD, VENC & DAC. */ + outw((inw(DM270_CLKC_MOD1) | + (DM270_CLKC_MOD1_COSD | DM270_CLKC_MOD1_CVENC | + DM270_CLKC_MOD1_CDAC)), + DM270_CLKC_MOD1); + + // Disable VENC & DAC + outw(0, DM270_VENC_VID01); + + /* Initialize OSD and VENC */ + bmpwin_addr = (fbinfo->fix.smem_start - CONFIG_DRAM_BASE) >> 5; + outw((bmpwin_addr >> 16), DM270_OSD_BMPWINADH); /* XXX potential contention between bmpwin0 & bmpwin1 */ + outw((bmpwin_addr & 0xffff), dm270fbpar->regaddr.bmpwinadl); + + osdmode = (DM270_OSD_OSDMODE_CS_CBCR | + DM270_OSD_OSDMODE_BCLUT_ROM | + DM270_OSD_OSDMODE_CABG_BLACK); + + if (dm270fbpar->cfg.disp_type == DISP_TYPE_COMP) { + vid01 = (DM270_VENC_VID01_CRCUT_1_5MHZ | + DM270_VENC_VID01_SETUP_0 | + DM270_VENC_VID01_RGBFLT_OFF | + DM270_VENC_VID01_YFLT_OFF | + DM270_VENC_VID01_COUTEN_ENABLE | + DM270_VENC_VID01_BLANK_NORMAL); + + vid02 = (DM270_VENC_VID02_SSMD_NTSCPAL | + DM270_VENC_VID02_SCMP_YES | + DM270_VENC_VID02_SYSW_DISABLE | + DM270_VENC_VID02_VSSW_CSYNC | /* XXX */ + DM270_VENC_VID02_SYNE_ENABLE | + DM270_VENC_VID02_BREN_DISABLE | + DM270_VENC_VID02_BRPL_ACTIVELOW | + DM270_VENC_VID02_BRWDTH_0); + } else if (dm270fbpar->cfg.disp_type == DISP_TYPE_LCD || + dm270fbpar->cfg.disp_type == DISP_TYPE_TFT || + dm270fbpar->cfg.disp_type == DISP_TYPE_CRT) { + } else if (dm270fbpar->cfg.disp_type == DISP_TYPE_EPSON) { + } else if (dm270fbpar->cfg.disp_type == DISP_TYPE_CASIO) { + } else { + } + + if (dm270fbpar->cfg.vidout_std == VID_FMT_NTSC) { + vid01 |= DM270_VENC_VID01_NTPLS_NTSC; + + osdmode |= (DM270_OSD_OSDMODE_ORSZ_X1 | + DM270_OSD_OSDMODE_FSINV_NORMAL); + + basepx = DM270FB_OSD_BASEPX_NTSC; /* 120 */ + basepy = DM270FB_OSD_BASEPY_NTSC; /* 18 */ + } else if (dm270fbpar->cfg.vidout_std == VID_FMT_PAL) { + vid01 |= DM270_VENC_VID01_NTPLS_PAL; + + osdmode |= (DM270_OSD_OSDMODE_ORSZ_X6_5 | + DM270_OSD_OSDMODE_FSINV_INVERTED); + + basepx = DM270FB_OSD_BASEPX_PAL; /* 144 */ + basepy = DM270FB_OSD_BASEPY_PAL; /* 22 */ + } else { + } + + for (ii = 0; ii < 16; ii += 2) { + outw(((ii + 1) << 8) | ii, + dm270fbpar->regaddr.wbmp + ii); + } + + outw(basepx, DM270_OSD_BASEPX); + outw(basepy, DM270_OSD_BASEPY); + outw(osdmode, DM270_OSD_OSDMODE); + outw(vid02, DM270_VENC_VID02); + outw(vid01, DM270_VENC_VID01); + } else { + bmpwin_addr = ((unsigned int)inw(DM270_OSD_BMPWINADH) << 16); + bmpwin_addr |= inw(dm270fbpar->regaddr.bmpwinadl); + fbinfo->fix.smem_start = (bmpwin_addr << 5) + CONFIG_DRAM_BASE; + fbinfo->screen_base = phys_to_virt(fbinfo->fix.smem_start); + DPRINTK("phys=0x%016lx virt=0x%08x len=%u\n", + fbinfo->fix.smem_start, + (unsigned int)fbinfo->screen_base, + fbinfo->fix.smem_len); + } + + DPRINTK("OSDMODE=0x%04x BASEPX=0x%04x BASEPY=0x%04x\n", + inw(DM270_OSD_OSDMODE), inw(DM270_OSD_BASEPX), + inw(DM270_OSD_BASEPY)); + DPRINTK("BMPWINADH=0x%04x BMPWINADL=0x%04x\n", + inw(DM270_OSD_BMPWINADH), inw(dm270fbpar->regaddr.bmpwinadl)); + DPRINTK("VID01=0x%04x VID02=0x%04x\n", + inw(DM270_VENC_VID01), inw(DM270_VENC_VID02)); +} + +static void +dm270fb_blank_display(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) | DM270_VENC_VID01_BLANK, DM270_VENC_VID01); + DPRINTK("Blank: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +static void +dm270fb_unblank_display(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) & ~DM270_VENC_VID01_BLANK, DM270_VENC_VID01); + DPRINTK("Unblank: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +/* + * FIXME: move LCD power stuff into dm270fb_dac_powerup() + * Also, I'm expecting that the backlight stuff should + * be handled differently. + */ +static void +dm270fb_backlight_on(struct fb_info *fbinfo) +{ + DPRINTK("Backlight on\n"); +#ifdef CONFIG_BOARD_IMPLDM270VP4 + outw(DM270_GIO_GIO06_BIT, DM270_GIO_BITSET0); +#endif +} + +/* + * FIXME: move LCD power stuff into dm270fb_dac_powerdown() + * Also, I'm expecting that the backlight stuff should + * be handled differently. + */ +static void +dm270fb_backlight_off(struct fb_info *fbinfo) +{ + DPRINTK("Backlight off\n"); +#ifdef CONFIG_BOARD_IMPLDM270VP4 + outw(DM270_GIO_GIO06_BIT, DM270_GIO_BITCLR0); +#endif +} + +static void +dm270fb_dac_powerup(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) | DM270_VENC_VID01_DAPD, DM270_VENC_VID01); + DPRINTK("DAC poweron: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +static void +dm270fb_dac_powerdown(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) & ~DM270_VENC_VID01_DAPD, DM270_VENC_VID01); + DPRINTK("DAC poweroff: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +static void +dm270fb_osd_enable(struct fb_info *fbinfo) +{ + struct dm270fb_par *dm270fbpar = (struct dm270fb_par *)fbinfo->par; + + outw(inw(dm270fbpar->regaddr.bmpwinmd) | DM270_OSD_BMPWINMD_OACT, + dm270fbpar->regaddr.bmpwinmd); + + DPRINTK("OSD enable: BMPWINMD=0x%04x\n", + inw(dm270fbpar->regaddr.bmpwinmd)); +} + +static void +dm270fb_osd_disable(struct fb_info *fbinfo) +{ + struct dm270fb_par *dm270fbpar = (struct dm270fb_par *)fbinfo->par; + + outw(inw(dm270fbpar->regaddr.bmpwinmd) & ~DM270_OSD_BMPWINMD_OACT, + dm270fbpar->regaddr.bmpwinmd); + + DPRINTK("OSD disable: BMPWINMD=0x%04x\n", + inw(dm270fbpar->regaddr.bmpwinmd)); +} + +static void +dm270fb_venc_enable(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) | (DM270_VENC_VID01_DAOE | + DM270_VENC_VID01_VENC), DM270_VENC_VID01); + + DPRINTK("VENC enable: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +static void +dm270fb_venc_disable(struct fb_info *fbinfo) +{ + outw(inw(DM270_VENC_VID01) & ~(DM270_VENC_VID01_DAOE | + DM270_VENC_VID01_VENC), DM270_VENC_VID01); + + DPRINTK("VENC disable: VID01=0x%04x\n", inw(DM270_VENC_VID01)); +} + +static int +dm270fb_set_palettereg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *fbinfo) +{ + unsigned int ccir601_y; + unsigned int ccir601_cb; + unsigned int ccir601_cr; + int too_long; + + if (regno >= DM270FB_NR_PALETTE) { + WPRINTK("regno %u exceed %u CLUT entries\n", + regno, DM270FB_NR_PALETTE); + return -EINVAL; + } + + /* + * CCIR-601 YCbCr Color Space Conversion Equation + * + * Y = ( 77R + 150G + 29B)/256 Range: 16 ~ 235 + * Cb = (-44R - 87G + 131B)/256 + 128 Range: 16 ~ 240 + * Cr = (131R - 110G - 21B)/256 + 128 Range: 16 ~ 240 + * + * R = Y + 1.371(Cr - 128) + * G = Y - 0.698(Cr - 128) - 0.336(Cb - 128) + * B = Y + 1.732(Cb - 128) + * + * where R, G and B are gamma-corrected values with a nominal range of 16 to 235 + * + * Y = 0.257R + 0.504G + 0.098B + 16 Range: 16 ~ 235 + * Cb = -0.148R - 0.291G + 0.439B + 128 Range: 16 ~ 240 + * Cr = 0.439R - 0.368G - 0.071B + 128 Range: 16 ~ 240 + * + * R = 1.164(Y - 16) + 1.596(Cr - 128) + * G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.392(Cb - 128) + * B = 1.164(Y - 16) + 2.017(Cb - 128) + * + * where R, G and B are gamma-corrected values with a range of 0 to 255 + */ + + ccir601_y = ((16843*red + 33030*green + 6423*blue)/65536 + 16) & 0xff; + ccir601_cb = ((-9699*red - 19071*green + 28770*blue)/65536 + 128) & 0xff; + ccir601_cr = ((28770*red - 24117*green - 4653*blue)/65536 + 128) & 0xff; + + too_long = 100000; + while ((inw(DM270_OSD_MISCCTL) & DM270_OSD_MISCCTL_CPBSY) && + (too_long-- > 0)); + + if (too_long <= 0) { + WPRINTK("timeout (MISCCTL=0x%04x)\n", inw(DM270_OSD_MISCCTL)); + return -ETIMEDOUT; + } + + outw((ccir601_y << 8) | ccir601_cb , DM270_OSD_CLUTRAMYCB); + +#if 0 + /* + * XXX + * discrepancy between description and code in + * DM270 Techincal Reference Manual Ver 1.2 Sect 12.7.1.2 Pg 274 + */ + too_long = 100000; + while ((inw(DM270_OSD_MISCCTL) & DM270_OSD_MISCCTL_CPBSY) && + (too_long-- > 0)); +#endif + + outw((ccir601_cr << 8) | (regno & 0xff), DM270_OSD_CLUTRAMCR); + return 0; +} + +/* -------------------- Helper routines ------------------------- */ + +static void +dm270fb_display_powerup(struct fb_info *fbinfo) +{ + DPRINTK("Display poweron\n"); + dm270fb_dac_powerup(fbinfo); + dm270fb_backlight_on(fbinfo); +} + +static void +dm270fb_display_powerdown(struct fb_info *fbinfo) +{ + DPRINTK("Display poweroff\n"); + dm270fb_backlight_off(fbinfo); + dm270fb_dac_powerdown(fbinfo); +} + +static void +dm270fb_display_enable(struct fb_info *fbinfo) +{ + DPRINTK("Display enable\n"); + dm270fb_osd_enable(fbinfo); + dm270fb_venc_enable(fbinfo); + dm270fb_display_powerup(fbinfo); +} + +static void +dm270fb_display_disable(struct fb_info *fbinfo) +{ + DPRINTK("Display disable\n"); + dm270fb_display_powerdown(fbinfo); + dm270fb_venc_disable(fbinfo); + dm270fb_osd_disable(fbinfo); +} + +static unsigned int +dm270fb_calc_linelength(struct fb_info *fbinfo) +{ + unsigned int linelength; + + /* + * Where width of data in SDRAM is not multiple of 32 bytes, padding + * must be done to make it multiple of 32 bytes + */ + linelength = ((((fbinfo->var.xres_virtual * fbinfo->var.bits_per_pixel) + + 255) >> 8) << 5); + fbinfo->var.xres_virtual = (linelength << 3) / + fbinfo->var.bits_per_pixel; + return linelength; +} + +/* + * dm270fb_decode_var - Get the hardware video params out of 'var'. + * @info: frame buffer structure that represents a single frame buffer + * @regval: hardware register values obtained from 'var' + */ +static int +dm270fb_decode_var(struct fb_info *fbinfo, struct dm270fb_regval *regval) +{ + fbinfo->fix.line_length = dm270fb_calc_linelength(fbinfo); + regval->bmpwinofst = (fbinfo->fix.line_length >> 5); + regval->bmpwinxl = fbinfo->var.xres; + regval->bmpwinxp = fbinfo->var.xoffset; + + regval->bmpwinmd = (DM270_OSD_BMPWINMD_CLUT_ROM | + DM270_OSD_BMPWINMD_OHZ_X1 | + DM270_OSD_BMPWINMD_OVZ_X1 | + DM270_OSD_BMPWINMD_BLND_0_8 | + DM270_OSD_BMPWINMD_TE_ENABLE); + + regval->vid01 = 0; + if (fbinfo->var.vmode & FB_VMODE_INTERLACED) { + regval->vid01 |= DM270_VENC_VID01_SCMD_INTERLACE; + } else if (fbinfo->var.vmode & FB_VMODE_NONINTERLACED) { + regval->vid01 |= DM270_VENC_VID01_SCMD_NONINTERLACE; + } + + regval->vid02 = 0; + if (fbinfo->var.sync & FB_SYNC_COMP_HIGH_ACT) { + regval->vid02 |= DM270_VENC_VID02_VSSW_CSYNC; + } + + if (fbinfo->var.vmode & FB_VMODE_DOUBLE) { + regval->bmpwinyl = fbinfo->var.yres; + regval->bmpwinyp = fbinfo->var.yoffset; + regval->bmpwinmd |= DM270_OSD_BMPWINMD_OFF_FIELD; + } else { + regval->bmpwinyl = (fbinfo->var.yres >> 1); + regval->bmpwinyp = (fbinfo->var.yoffset >> 1); + regval->bmpwinmd |= DM270_OSD_BMPWINMD_OFF_FRAME; + } + + switch (fbinfo->var.bits_per_pixel) { + case 1: regval->bmpwinmd |= DM270_OSD_BMPWINMD_BMW_1BPP; break; + case 2: regval->bmpwinmd |= DM270_OSD_BMPWINMD_BMW_2BPP; break; + case 4: regval->bmpwinmd |= DM270_OSD_BMPWINMD_BMW_4BPP; break; + case 8: regval->bmpwinmd |= DM270_OSD_BMPWINMD_BMW_8BPP; break; + default: + WPRINTK("depth %u bpp not supported???\n", + fbinfo->var.bits_per_pixel); + return -EINVAL; + } + + return 0; +} + +/* + * dm270fb_map_graphics_memory - Allocates DRAM memory for frame buffer. + * @info: frame buffer structure that represents a single frame buffer + * + * This memory is remapped into a non-cached, non-buffered, memory region + * to allow pixel writes to occur without flushing the cache. Once this + * area is remapped, all virtual memory access to the graphics memory + * should occur at the new region. + */ +static int __init +dm270fb_map_graphics_memory(struct fb_info *fbinfo) +{ + unsigned long adrs; + unsigned long size; + + /* + * We reserve size of the framebuffer. + */ + size = PAGE_ALIGN(fbinfo->fix.smem_len); + if (0 == size) { + WPRINTK("size=%u\n", fbinfo->fix.smem_len); + return -EINVAL; + } + if (size > (PAGE_SIZE << MAX_ORDER)) { + WPRINTK("size %u exceed %lu\n", fbinfo->fix.smem_len, + (PAGE_SIZE << MAX_ORDER)); + return -EINVAL; + } + fbinfo->screen_base = (void *)__get_free_pages(GFP_KERNEL, + get_order(size)); + if (NULL == fbinfo->screen_base) { + WPRINTK("alloc failed: virt=0x%08x size=%u " + "PAGESIZE=%lu MAX_ORDER=%u\n", + (unsigned int)fbinfo->screen_base, fbinfo->fix.smem_len, + PAGE_SIZE, MAX_ORDER); + return -ENOMEM; + } + fbinfo->fix.smem_len = size; + adrs = (unsigned long)fbinfo->screen_base; + while (size > 0) { + SetPageReserved(virt_to_page(adrs)); + adrs += PAGE_SIZE; + size -= PAGE_SIZE; + } + fbinfo->fix.smem_start = virt_to_phys(fbinfo->screen_base); + DPRINTK("phys=0x%016lx virt=0x%08x len=%u\n", fbinfo->fix.smem_start, + (unsigned int)fbinfo->screen_base, + fbinfo->fix.smem_len); + memset(fbinfo->screen_base, 0, fbinfo->fix.smem_len); + return 0; +} + +/* + * dm270fb_unmap_graphics_memory - Frees DRAM memory of frame buffer. + * @info: frame buffer structure that represents a single frame buffer + */ +static void +dm270fb_unmap_graphics_memory(struct fb_info *fbinfo) +{ + unsigned long adrs; + unsigned long size; + + DPRINTK("phys=0x%016lx virt=0x%08x len=%u\n", + fbinfo->fix.smem_start, + (unsigned int)fbinfo->screen_base, + fbinfo->fix.smem_len); + + if (fbinfo->screen_base) { + size = fbinfo->fix.smem_len; + adrs = (unsigned long)fbinfo->screen_base; + while (size > 0) { + ClearPageReserved(virt_to_page(adrs)); + adrs += PAGE_SIZE; + size -= PAGE_SIZE; + } + free_pages((unsigned long)fbinfo->screen_base, get_order(fbinfo->fix.smem_len)); + fbinfo->fix.smem_len = 0; + fbinfo->fix.smem_start = 0; + fbinfo->screen_base = NULL; + } +} + +/* + * =========================================================================== + */ + +/* + * dm270fb_check_var - Optional function. Validates a var passed in. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Checks to see if the hardware supports the state requested by + * var passed in. This function does not alter the hardware state!!! + * This means the data stored in struct fb_info and struct dm270fb_par do + * not change. This includes the var inside of struct fb_info. + * Do NOT change these. This function can be called on its own if we + * intent to only test a mode and not actually set it. The stuff in + * modedb.c is a example of this. If the var passed in is slightly + * off by what the hardware can support then we alter the var PASSED in + * to what we can do. If the hardware doesn't support mode change + * a -EINVAL will be returned by the upper layers. You don't need to + * implement this function then. If you hardware doesn't support + * changing the resolution then this function is not needed. In this + * case the driver woudl just provide a var that represents the static + * state the screen is in. + * + * If a value doesn't fit, round it up, if it's too big, return -EINVAL. + * + * Suggestion: Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + * + * Returns negative errno on error, or zero on success. + */ +static int +dm270fb_check_var(struct fb_var_screeninfo *fbvar, struct fb_info *fbinfo) +{ + switch (fbvar->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + /* for bpp <= 8, length of red = length of green = length of blue = bpp */ + fbvar->red.offset = 0; + fbvar->red.length = fbvar->bits_per_pixel; + fbvar->red.msb_right = 0; + + fbvar->green.offset = 0; + fbvar->green.length = fbvar->bits_per_pixel; + fbvar->green.msb_right = 0; + + fbvar->blue.offset = 0; + fbvar->blue.length = fbvar->bits_per_pixel; + fbvar->blue.msb_right = 0; + + fbvar->transp.offset = 0; + fbvar->transp.length = 0; + fbvar->transp.msb_right = 0; + break; + default: + WPRINTK("unsupported depth: %u bpp\n", fbvar->bits_per_pixel); + return -EINVAL; + } + + if (fbvar->xres < DM270FB_XRES_MIN) { + WPRINTK("width %u round up to %u\n", + fbvar->xres, DM270FB_XRES_MIN); + fbvar->xres = DM270FB_XRES_MIN; + } + if (fbvar->yres < DM270FB_YRES_MIN) { + WPRINTK("height %u round up to %u\n", + fbvar->yres, DM270FB_YRES_MIN); + fbvar->yres = DM270FB_YRES_MIN; + } + if (fbvar->xres > DM270FB_XRES_MAX) { + WPRINTK("width %u round down to %u\n", + fbvar->xres, DM270FB_XRES_MAX); + fbvar->xres = DM270FB_XRES_MAX; + } + if (fbvar->yres > DM270FB_YRES_MAX) { + WPRINTK("height %u round down to %u\n", + fbvar->yres, DM270FB_YRES_MAX); + fbvar->yres = DM270FB_YRES_MAX; + } + + if (fbvar->xres_virtual < fbvar->xres) { + WPRINTK("virtual x resolution %u round up to " + "physical x resolution %u\n", + fbvar->xres_virtual, fbvar->xres); + fbvar->xres_virtual = fbvar->xres; + } + if (fbvar->yres_virtual < fbvar->yres) { + WPRINTK("virtual y resolution %u round up to " + "physical y resolution %u\n", + fbvar->yres_virtual, fbvar->yres); + fbvar->yres_virtual = fbvar->yres; + } + + if (((fbvar->xres_virtual * fbvar->yres_virtual * fbvar->bits_per_pixel) + >> 3) > fbinfo->fix.smem_len) { + WPRINTK("insufficient memory for virtual screen (%u, %u, %u)\n", + fbvar->xres_virtual, fbvar->yres_virtual, + fbvar->bits_per_pixel); + return -ENOMEM; + } + + fbvar->nonstd = 0; + fbvar->height = -1; + fbvar->width = -1; + return 0; +} + +/* + * dm270fb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + * Using the fb_var_screeninfo in fb_info we set the resolution of the + * this particular framebuffer. This function alters the par AND the + * fb_fix_screeninfo stored in fb_info. It doesn't alter var in + * fb_info since we are using that data. This means we depend on the + * data in var inside fb_info to be supported by the hardware. + * dm270fb_check_var is always called before dm270fb_set_par to ensure this. + * Again if you can't change the resolution you don't need this function. + * + * Configures OSD based on entries in var parameter. Settings are + * only written to the controller if changes were made. + */ +static int +dm270fb_set_par(struct fb_info *fbinfo) +{ + struct dm270fb_par *dm270fbpar = (struct dm270fb_par *)fbinfo->par; + struct dm270fb_regval regval; + int retval; + + DPRINTK("Configuring TI TMS320DM270 OSD\n"); + + if ((retval = dm270fb_decode_var(fbinfo, ®val))) + return retval; + + /* + * XXX + * Only DM270_VENC_VID01_SCMD & DM270_VENC_VID02_VSSW are tracked. + * DM270_OSD_BMPWINMD_OACT is not tracked. + */ + dm270fbpar->regval = regval; /* struct copy */ + + outw((inw(DM270_VENC_VID02) & ~(DM270_VENC_VID02_VSSW)) | + regval.vid02, DM270_VENC_VID02); + outw((inw(DM270_VENC_VID01) & ~(DM270_VENC_VID01_SCMD)) | + regval.vid01, DM270_VENC_VID01); + + outw((inw(dm270fbpar->regaddr.bmpwinmd) & DM270_OSD_BMPWINMD_OACT) | + regval.bmpwinmd, dm270fbpar->regaddr.bmpwinmd); + outw(regval.bmpwinofst, dm270fbpar->regaddr.bmpwinofst); + outw(regval.bmpwinxl, dm270fbpar->regaddr.bmpwinxl); + outw(regval.bmpwinyl, dm270fbpar->regaddr.bmpwinyl); + outw(regval.bmpwinxp, dm270fbpar->regaddr.bmpwinxp); + outw(regval.bmpwinyp, dm270fbpar->regaddr.bmpwinyp); + + DPRINTK("VID01=0x%04x VID02=0x%04x\n", + inw(DM270_VENC_VID01), inw(DM270_VENC_VID02)); + DPRINTK("BMPWINMD=0x%04x BMPWINOFST=0x%04x\n", + inw(dm270fbpar->regaddr.bmpwinmd), + inw(dm270fbpar->regaddr.bmpwinofst)); + DPRINTK("BMPWINXL=0x%04x BMPWINYL=0x%04x\n", + inw(dm270fbpar->regaddr.bmpwinxl), + inw(dm270fbpar->regaddr.bmpwinyl)); + DPRINTK("BMPWINXP=0x%04x BMPWINYP=0x%04x\n", + inw(dm270fbpar->regaddr.bmpwinxp), + inw(dm270fbpar->regaddr.bmpwinyp)); + return 0; +} + +/* + * dm270fb_setcolreg - Optional function. Sets a color register. + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Things to take into consideration are how many color registers, if + * any, are supported with the current color visual. With truecolor mode + * no color palettes are supported. Here a psuedo palette is created + * which we store the value in pseudo_palette in struct fb_info. For + * pseudocolor mode we have a limited color palette. To deal with this + * we can program what color is displayed for a particular pixel value. + * DirectColor is similar in that we can program each color field. If + * we have a static colormap we don't need to implement this function. + * + * Returns negative errno on error, or zero on success. + */ +static int +dm270fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *fbinfo) +{ + DPRINTK("regno=%u red=%u green=%u blue=%u transp=%u\n", + regno, red, green, blue, transp); + + /* + * If grayscale is true, we convert the RGB value to + * grayscale regardless of what visual we are using. + */ + if (fbinfo->var.grayscale) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (19595 * red + 38470 * green + 7471 * blue) >> 16; + } + + switch (fbinfo->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + /* + * Pseudocolour: + * 8 8 + * pixel --/--+--/--> red lut --> red dac + * | 8 + * +--/--> green lut --> green dac + * | 8 + * +--/--> blue lut --> blue dac + */ + if (regno >= fbinfo->cmap.len || regno >= DM270FB_NR_PALETTE) { + WPRINTK("regno %u exceed cmap length %u (max %u)\n", + regno, fbinfo->cmap.len, + DM270FB_NR_PALETTE); + return -EINVAL; + } + + return dm270fb_set_palettereg(regno, red, green, blue, + transp, fbinfo); + default: + WPRINTK("invalid visual %u\n", fbinfo->fix.visual); + return -EINVAL; + } + + return 0; +} + +/* + * dm270fb_blank - NOT a required function. Blanks the display. + * @blank: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank == 2: suspend vsync + * blank == 3: suspend hsync + * blank == 4: powerdown + * + * Returns negative errno on error, or zero on success. + */ +/* + * Formal definition of the VESA spec: + * On + * This refers to the state of the display when it is in full operation + * Stand-By + * This defines an optional operating state of minimal power reduction with + * the shortest recovery time + * Suspend + * This refers to a level of power management in which substantial power + * reduction is achieved by the display. The display can have a longer + * recovery time from this state than from the Stand-by state + * Off + * This indicates that the display is consuming the lowest level of power + * and is non-operational. Recovery from this state may optionally require + * the user to manually power on the monitor + * + * Now, the fbdev driver adds an additional state, (blank), where they + * turn off the video (maybe by colormap tricks), but don't mess with the + * video itself: think of it semantically between on and Stand-By. + * + * So here's what we should do in our fbdev blank routine: + * + * VESA_NO_BLANKING (mode 0) Video on, front/back light on + * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off + * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off + * VESA_POWERDOWN (mode 3) Video off, front/back light off + * + * This will match the matrox implementation. + */ +static int +dm270fb_blank(int blank, struct fb_info *fbinfo) +{ + DPRINTK("blank=%d\n", blank); + + if (blank) { + dm270fb_blank_display(fbinfo); + } else { + dm270fb_unblank_display(fbinfo); + dm270fb_dac_powerup(fbinfo); + } + if (blank > 0) { + switch (blank - 1) { + case VESA_NO_BLANKING: + dm270fb_display_powerup(fbinfo); + break; + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + dm270fb_dac_powerdown(fbinfo); + break; + case VESA_POWERDOWN: + dm270fb_display_powerdown(fbinfo); + break; + default: + WPRINTK("invalid VESA blanking level %d\n", blank); + return -EINVAL; + } + } + + return 0; +} + +/* + * dm270fb_pan_display - NOT a required function. Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + * + * Returns negative errno on error, or zero on success. + */ +static int +dm270fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + return -EINVAL; +} + +static int +dm270fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *fbinfo) +{ + int ii; + int jj; + int retval = 0; + + switch (cmd) { +#ifdef DM270FB_DEBUG + case FBIOPUT_DM270_COLORIMG: + DPRINTK("FBIOPUT_DM270_COLORIMG\n"); + for (ii = 0; ii < fbinfo->var.yres; ii++) { + for (jj = 0; jj < fbinfo->var.xres; jj++) { + *((unsigned char *)fbinfo->screen_base + + ii*fbinfo->var.xres + jj) = arg; + } + } + break; + + case FBCMD_DM270_PRINT_FBUF: + DPRINTK("FBCMD_DM270_PRINT_FBUF\n"); + if (arg < 0 || arg >= fbinfo->var.yres) { + WPRINTK("arg=%ld (%u)\n", arg, fbinfo->var.yres); + return -EINVAL; + } + for (ii = 0; ii < fbinfo->var.xres; ii++) { + unsigned char *fbaddr = + (unsigned char *)fbinfo->screen_base + + arg*fbinfo->var.xres + ii; + if (!(ii % 16)) { + printk("\n%p: %02x ", fbaddr, *fbaddr); + } else { + printk("%02x ", *fbaddr); + } + } + printk("\n"); + break; + + case FBCMD_DM270_PRINT_REG: + DPRINTK("FBCMD_DM270_PRINT_REG\n"); + + DPRINTK("Clock Controller\n" ); + DPRINTK("================\n" ); + DPRINTK("PLLA = 0x%08x\n", inw(DM270_CLKC_PLLA)); + DPRINTK("PLLB = 0x%08x\n", inw(DM270_CLKC_PLLB)); + DPRINTK("CLKC = 0x%08x\n", inw(DM270_CLKC_CLKC)); + DPRINTK("SEL = 0x%08x\n", inw(DM270_CLKC_SEL)); + DPRINTK("DIV = 0x%08x\n", inw(DM270_CLKC_DIV)); + DPRINTK("BYP = 0x%08x\n", inw(DM270_CLKC_BYP)); + DPRINTK("MMCCLK = 0x%08x\n", inw(DM270_CLKC_MMCCLK)); + DPRINTK("MOD0 = 0x%08x\n", inw(DM270_CLKC_MOD0)); + DPRINTK("MOD1 = 0x%08x\n", inw(DM270_CLKC_MOD1)); + DPRINTK("MOD2 = 0x%08x\n", inw(DM270_CLKC_MOD2)); + DPRINTK("LPCTL0 = 0x%08x\n", inw(DM270_CLKC_LPCTL0)); + DPRINTK("LPCTL1 = 0x%08x\n", inw(DM270_CLKC_LPCTL1)); + DPRINTK("OSEL = 0x%08x\n", inw(DM270_CLKC_OSEL)); + DPRINTK("O0DIV = 0x%08x\n", inw(DM270_CLKC_O0DIV)); + DPRINTK("O1DIV = 0x%08x\n", inw(DM270_CLKC_O1DIV)); + DPRINTK("O2DIV = 0x%08x\n", inw(DM270_CLKC_O2DIV)); + DPRINTK("PWM0C = 0x%08x\n", inw(DM270_CLKC_PWM0C)); + DPRINTK("PWM0H = 0x%08x\n", inw(DM270_CLKC_PWM0H)); + DPRINTK("PWM1C = 0x%08x\n", inw(DM270_CLKC_PWM1C)); + DPRINTK("PWM1H = 0x%08x\n", inw(DM270_CLKC_PWM1H)); + DPRINTK("\n"); + + DPRINTK("OSD - On-Screen Display\n" ); + DPRINTK("=======================\n" ); + DPRINTK("OSDMODE = 0x%04x\n", inw(DM270_OSD_OSDMODE)); + DPRINTK("VIDWINMD = 0x%04x\n", inw(DM270_OSD_VIDWINMD)); + DPRINTK("BMPWIN0MD = 0x%04x\n", inw(DM270_OSD_BMPWIN0MD)); + DPRINTK("ATRMD = 0x%04x\n", inw(DM270_OSD_ATRMD)); + DPRINTK("RECTCUR = 0x%04x\n", inw(DM270_OSD_RECTCUR)); + DPRINTK("VIDWIN0OFST = 0x%04x\n", inw(DM270_OSD_VIDWIN0OFST)); + DPRINTK("VIDWIN1OFST = 0x%04x\n", inw(DM270_OSD_VIDWIN1OFST)); + DPRINTK("BMPWIN0OFST = 0x%04x\n", inw(DM270_OSD_BMPWIN0OFST)); + DPRINTK("BMPWIN1OFST = 0x%04x\n", inw(DM270_OSD_BMPWIN1OFST)); + DPRINTK("VIDWINADH = 0x%04x\n", inw(DM270_OSD_VIDWINADH)); + DPRINTK("VIDWIN0ADL = 0x%04x\n", inw(DM270_OSD_VIDWIN0ADL)); + DPRINTK("VIDWIN1ADL = 0x%04x\n", inw(DM270_OSD_VIDWIN1ADL)); + DPRINTK("BMPWINADH = 0x%04x\n", inw(DM270_OSD_BMPWINADH)); + DPRINTK("BMPWIN0ADL = 0x%04x\n", inw(DM270_OSD_BMPWIN0ADL)); + DPRINTK("BMPWIN1ADL = 0x%04x\n", inw(DM270_OSD_BMPWIN1ADL)); + DPRINTK("BASEPX = 0x%04x\n", inw(DM270_OSD_BASEPX)); + DPRINTK("BASEPY = 0x%04x\n", inw(DM270_OSD_BASEPY)); + DPRINTK("VIDWIN0XP = 0x%04x\n", inw(DM270_OSD_VIDWIN0XP)); + DPRINTK("VIDWIN0YP = 0x%04x\n", inw(DM270_OSD_VIDWIN0YP)); + DPRINTK("VIDWIN0XL = 0x%04x\n", inw(DM270_OSD_VIDWIN0XL)); + DPRINTK("VIDWIN0YL = 0x%04x\n", inw(DM270_OSD_VIDWIN0YL)); + DPRINTK("VIDWIN1XP = 0x%04x\n", inw(DM270_OSD_VIDWIN1XP)); + DPRINTK("VIDWIN1YP = 0x%04x\n", inw(DM270_OSD_VIDWIN1YP)); + DPRINTK("VIDWIN1XL = 0x%04x\n", inw(DM270_OSD_VIDWIN1XL)); + DPRINTK("VIDWIN1YL = 0x%04x\n", inw(DM270_OSD_VIDWIN1YL)); + DPRINTK("BMPWIN0XP = 0x%04x\n", inw(DM270_OSD_BMPWIN0XP)); + DPRINTK("BMPWIN0YP = 0x%04x\n", inw(DM270_OSD_BMPWIN0YP)); + DPRINTK("BMPWIN0XL = 0x%04x\n", inw(DM270_OSD_BMPWIN0XL)); + DPRINTK("BMPWIN0YL = 0x%04x\n", inw(DM270_OSD_BMPWIN0YL)); + DPRINTK("BMPWIN1XP = 0x%04x\n", inw(DM270_OSD_BMPWIN1XP)); + DPRINTK("BMPWIN1YP = 0x%04x\n", inw(DM270_OSD_BMPWIN1YP)); + DPRINTK("BMPWIN1XL = 0x%04x\n", inw(DM270_OSD_BMPWIN1XL)); + DPRINTK("BMPWIN1YL = 0x%04x\n", inw(DM270_OSD_BMPWIN1YL)); + DPRINTK("CURXP = 0x%04x\n", inw(DM270_OSD_CURXP)); + DPRINTK("CURYP = 0x%04x\n", inw(DM270_OSD_CURYP)); + DPRINTK("CURXL = 0x%04x\n", inw(DM270_OSD_CURXL)); + DPRINTK("CURYL = 0x%04x\n", inw(DM270_OSD_CURYL)); + DPRINTK("W0BMP01 = 0x%04x\n", inw(DM270_OSD_W0BMP01)); + DPRINTK("W0BMP23 = 0x%04x\n", inw(DM270_OSD_W0BMP23)); + DPRINTK("W0BMP45 = 0x%04x\n", inw(DM270_OSD_W0BMP45)); + DPRINTK("W0BMP67 = 0x%04x\n", inw(DM270_OSD_W0BMP67)); + DPRINTK("W0BMP89 = 0x%04x\n", inw(DM270_OSD_W0BMP89)); + DPRINTK("W0BMPAB = 0x%04x\n", inw(DM270_OSD_W0BMPAB)); + DPRINTK("W0BMPCD = 0x%04x\n", inw(DM270_OSD_W0BMPCD)); + DPRINTK("W0BMPEF = 0x%04x\n", inw(DM270_OSD_W0BMPEF)); + DPRINTK("W1BMP01 = 0x%04x\n", inw(DM270_OSD_W1BMP01)); + DPRINTK("W1BMP23 = 0x%04x\n", inw(DM270_OSD_W1BMP23)); + DPRINTK("W1BMP45 = 0x%04x\n", inw(DM270_OSD_W1BMP45)); + DPRINTK("W1BMP67 = 0x%04x\n", inw(DM270_OSD_W1BMP67)); + DPRINTK("W1BMP89 = 0x%04x\n", inw(DM270_OSD_W1BMP89)); + DPRINTK("W1BMPAB = 0x%04x\n", inw(DM270_OSD_W1BMPAB)); + DPRINTK("W1BMPCD = 0x%04x\n", inw(DM270_OSD_W1BMPCD)); + DPRINTK("W1BMPEF = 0x%04x\n", inw(DM270_OSD_W1BMPEF)); + DPRINTK("MISCCTL = 0x%04x\n", inw(DM270_OSD_MISCCTL)); + DPRINTK("CLUTRAMYCB = 0x%04x\n", inw(DM270_OSD_CLUTRAMYCB)); + DPRINTK("CLUTRAMCR = 0x%04x\n", inw(DM270_OSD_CLUTRAMCR)); + DPRINTK("PPVWIN0ADH = 0x%04x\n", inw(DM270_OSD_PPVWIN0ADH)); + DPRINTK("PPVWIN0ADL = 0x%04x\n", inw(DM270_OSD_PPVWIN0ADL)); + + DPRINTK("Video Encoder\n" ); + DPRINTK("=============\n" ); + DPRINTK("VID01 = 0x%04x\n", inw(DM270_VENC_VID01)); + DPRINTK("VID02 = 0x%04x\n", inw(DM270_VENC_VID02)); + DPRINTK("DLCD1 = 0x%04x\n", inw(DM270_VENC_DLCD1)); + DPRINTK("DLCD2 = 0x%04x\n", inw(DM270_VENC_DLCD2)); + DPRINTK("DCLKPTN0E = 0x%04x\n", inw(DM270_VENC_DCLKPTN0E)); + DPRINTK("DCLKPTN1E = 0x%04x\n", inw(DM270_VENC_DCLKPTN1E)); + DPRINTK("DCLKPTN2E = 0x%04x\n", inw(DM270_VENC_DCLKPTN2E)); + DPRINTK("DCLKPTN3E = 0x%04x\n", inw(DM270_VENC_DCLKPTN3E)); + DPRINTK("DCLKPTN0O = 0x%04x\n", inw(DM270_VENC_DCLKPTN0O)); + DPRINTK("DCLKPTN1O = 0x%04x\n", inw(DM270_VENC_DCLKPTN1O)); + DPRINTK("DCLKPTN2O = 0x%04x\n", inw(DM270_VENC_DCLKPTN2O)); + DPRINTK("DCLKPTN3O = 0x%04x\n", inw(DM270_VENC_DCLKPTN3O)); + DPRINTK("DCLKSTPHE = 0x%04x\n", inw(DM270_VENC_DCLKSTPHE)); + DPRINTK("DCLKSTPHO = 0x%04x\n", inw(DM270_VENC_DCLKSTPHO)); + DPRINTK("DCLKVLDH = 0x%04x\n", inw(DM270_VENC_DCLKVLDH)); + DPRINTK("DCLKSTPV = 0x%04x\n", inw(DM270_VENC_DCLKSTPV)); + DPRINTK("DCLKVLDV = 0x%04x\n", inw(DM270_VENC_DCLKVLDV)); + DPRINTK("HVPWIDTH = 0x%04x\n", inw(DM270_VENC_HVPWIDTH)); + DPRINTK("HINTERVL = 0x%04x\n", inw(DM270_VENC_HINTERVL)); + DPRINTK("HSTART = 0x%04x\n", inw(DM270_VENC_HSTART)); + DPRINTK("HVALID = 0x%04x\n", inw(DM270_VENC_HVALID)); + DPRINTK("VINTERVL = 0x%04x\n", inw(DM270_VENC_VINTERVL)); + DPRINTK("VSTART = 0x%04x\n", inw(DM270_VENC_VSTART)); + DPRINTK("VVALID = 0x%04x\n", inw(DM270_VENC_VVALID)); + DPRINTK("HDELAY = 0x%04x\n", inw(DM270_VENC_HDELAY)); + DPRINTK("VDELAY = 0x%04x\n", inw(DM270_VENC_VDELAY)); + DPRINTK("CULLLINE = 0x%04x\n", inw(DM270_VENC_CULLLINE)); + DPRINTK("PWMCTRL = 0x%04x\n", inw(DM270_VENC_PWMCTRL)); + DPRINTK("PWMHPRD = 0x%04x\n", inw(DM270_VENC_PWMHPRD)); + DPRINTK("RGBLEVEL = 0x%04x\n", inw(DM270_VENC_RGBLEVEL)); + DPRINTK("ATR0 = 0x%04x\n", inw(DM270_VENC_ATR0)); + DPRINTK("ATR1 = 0x%04x\n", inw(DM270_VENC_ATR1)); + DPRINTK("ATR2 = 0x%04x\n", inw(DM270_VENC_ATR2)); + DPRINTK("REC656 = 0x%04x\n", inw(DM270_VENC_REC656)); + DPRINTK("EPSON_LCD = 0x%04x\n", inw(DM270_VENC_EPSON_LCD)); + DPRINTK("GCPDATA = 0x%04x\n", inw(DM270_VENC_GCPDATA)); + DPRINTK("CASIO = 0x%04x\n", inw(DM270_VENC_CASIO)); + DPRINTK("DOUTCTL = 0x%04x\n", inw(DM270_VENC_DOUTCTL)); + break; +#endif + + default: + WPRINTK("cmd=0x%08x\n", cmd); + return -EINVAL; + } + + return retval; +} + +static struct fb_ops dm270fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = dm270fb_check_var, + .fb_set_par = dm270fb_set_par, + .fb_setcolreg = dm270fb_setcolreg, + .fb_blank = dm270fb_blank, + .fb_pan_display = dm270fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_ioctl = dm270fb_ioctl, +}; + +/* + * =========================================================================== + */ + +#if 0 +/* + * These parameters give + * 640x480, hsync 31.5kHz, vsync 60Hz + */ +static struct fb_videomode __devinitdata dm270fb_default_mode = { + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 56, + .right_margin = 16, + .upper_margin = 34, + .lower_margin = 9, + .hsync_len = 88, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; +#endif + +/* + * Parse dm270fb options. + * Usage: video=dm270: + */ +static int __init +dm270fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) { + DPRINTK("options=%p\n", options); + return 0; + } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + + if (!strncmp(this_opt, "noaccel", 7)) { + dm270fb_bootcfg.noaccel = 1; + } else if (!strncmp(this_opt, "nopan", 5)) { + dm270fb_bootcfg.nopan = 1; + } else if (!strncmp(this_opt, "nowrap", 6)) { + dm270fb_bootcfg.nowrap = 1; + } else if (!strncmp(this_opt, "nohwcursor", 10)) { + dm270fb_bootcfg.nohwcursor = 1; + } else if (!strncmp(this_opt, "noinit", 6)) { + dm270fb_bootcfg.noinit = 1; + } else if (!strncmp(this_opt, "romclut", 7)) { + dm270fb_bootcfg.cmap_static = 1; + } else if (!strncmp(this_opt, "vsync", 5)) { + dm270fb_bootvar.sync &= ~FB_SYNC_COMP_HIGH_ACT; + } else if (!strncmp(this_opt, "grayscale", 9)) { + dm270fb_bootvar.grayscale = 1; + } else if (!strncmp(this_opt, "doublescan", 10)) { + dm270fb_bootvar.vmode |= FB_VMODE_DOUBLE; + } else if (!strncmp(this_opt, "font:", 5)) { + strncpy(dm270fb_bootcfg.fontname, this_opt+5, + sizeof(dm270fb_bootcfg.fontname)-1); + } else if (!strncmp(this_opt, "display:", 8)) { + if (!strncmp(this_opt+8, "comp", 4)) + dm270fb_bootcfg.disp_type = DISP_TYPE_COMP; + else if (!strncmp(this_opt+8, "lcd", 3)) + dm270fb_bootcfg.disp_type = DISP_TYPE_LCD; + else if (!strncmp(this_opt+8, "tft", 3)) + dm270fb_bootcfg.disp_type = DISP_TYPE_TFT; + else if (!strncmp(this_opt+8, "crt", 3)) + dm270fb_bootcfg.disp_type = DISP_TYPE_CRT; + else if (!strncmp(this_opt+8, "epson", 5)) + dm270fb_bootcfg.disp_type = DISP_TYPE_EPSON; + else if (!strncmp(this_opt+8, "casio", 5)) + dm270fb_bootcfg.disp_type = DISP_TYPE_CASIO; + } else if (!strncmp(this_opt, "vidfmt:", 7)) { + if (!strncmp(this_opt+7, "ntsc", 4)) + dm270fb_bootcfg.vidout_std = VID_FMT_NTSC; + else if (!strncmp(this_opt+7, "pal", 3)) + dm270fb_bootcfg.vidout_std = VID_FMT_PAL; + } else if (!strncmp(this_opt, "vidscan:", 8)) { + if (!strncmp(this_opt+7, "interlace", 9)) + dm270fb_bootvar.vmode |= FB_VMODE_INTERLACED; + else if (!strncmp(this_opt+7, "noninterlace", 12)) + dm270fb_bootvar.vmode &= ~FB_VMODE_INTERLACED; + } else if (!strncmp(this_opt, "width:", 6)) { + dm270fb_bootvar.xres = simple_strtoul(this_opt+6, NULL, 0); + } else if (!strncmp(this_opt, "height:", 7)) { + dm270fb_bootvar.yres = simple_strtoul(this_opt+7, NULL, 0); + } else if (!strncmp(this_opt, "bpp:", 4)) { + dm270fb_bootvar.bits_per_pixel = simple_strtoul(this_opt+4, NULL, 0); + } else if (!strncmp(this_opt, "hswidth:", 8)) { + dm270fb_bootvar.hsync_len = simple_strtoul(this_opt+8, + NULL, 0); + } else if (!strncmp(this_opt, "vswidth:", 8)) { + dm270fb_bootvar.vsync_len = simple_strtoul(this_opt+8, + NULL, 0); + } else { + dm270fb_bootcfg.mode_option = this_opt; + } + } + + return 0; +} + +static int __init +dm270fb_init_fbinfo(struct fb_info *fbinfo, char *name) +{ + struct dm270fb_par *dm270fbpar; + int maxlen; + int retval = 0; + + if (!fbinfo) { + WPRINTK("NULL\n"); + return -EINVAL; + } + + dm270fbpar = kmalloc(sizeof(struct dm270fb_par), GFP_KERNEL); + if (!dm270fbpar) { + WPRINTK("par alloc failed\n"); + return -ENOMEM; + } + + memset(dm270fbpar, 0, sizeof(struct dm270fb_par)); + memset(fbinfo, 0, sizeof(struct fb_info)); + + /* copy boot options */ + dm270fbpar->cfg = dm270fb_bootcfg; /* struct copy */ + fbinfo->var = dm270fb_bootvar; /* struct copy */ + + maxlen = sizeof(fbinfo->fix.id) - 1; + strncpy(fbinfo->fix.id, name, maxlen); /* max length 15 */ + fbinfo->fix.id[maxlen] = 0; + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.visual = (dm270fbpar->cfg.cmap_static) ? + FB_VISUAL_STATIC_PSEUDOCOLOR : FB_VISUAL_PSEUDOCOLOR; + fbinfo->fix.xpanstep = (dm270fbpar->cfg.nopan) ? 0 : 1; + fbinfo->fix.ypanstep = (dm270fbpar->cfg.nopan) ? 0 : 1; + fbinfo->fix.ywrapstep = (dm270fbpar->cfg.nowrap) ? 0 : 1; + fbinfo->fix.line_length = dm270fb_calc_linelength(fbinfo); + if (dm270fbpar->cfg.noaccel) { + fbinfo->fix.accel = FB_ACCEL_NONE; + } else { + fbinfo->fix.accel = FB_ACCEL_DM270; + } + + /* initialize frame-buffer */ + fbinfo->fix.smem_len = (DM270FB_XRES_MAX * DM270FB_YRES_MAX * + DM270FB_BPP_MAX) >> 3; /* frame-buffer size */ + + if (!dm270fbpar->cfg.noinit) { + if ((retval = dm270fb_map_graphics_memory(fbinfo))) { + WPRINTK("frame buffer alloc failed\n"); + retval = -ENOMEM; + goto ret_free_par; + } + } + + /* initialize register pointers */ + dm270fbpar->regaddr.bmpwinmd = DM270_OSD_BMPWIN0MD; + dm270fbpar->regaddr.bmpwinofst = DM270_OSD_BMPWIN0OFST; + dm270fbpar->regaddr.bmpwinadl = DM270_OSD_BMPWIN0ADL; + dm270fbpar->regaddr.bmpwinxp = DM270_OSD_BMPWIN0XP; + dm270fbpar->regaddr.bmpwinyp = DM270_OSD_BMPWIN0YP; + dm270fbpar->regaddr.bmpwinxl = DM270_OSD_BMPWIN0XL; + dm270fbpar->regaddr.bmpwinyl = DM270_OSD_BMPWIN0YL; + dm270fbpar->regaddr.wbmp = DM270_OSD_W0BMP01; + + /* enable clock to VENC & OSD */ + fbinfo->par = dm270fbpar; + dm270fb_init_hw(fbinfo); + + if (!dm270fbpar->cfg.noinit) { + /* disable video encoder while initializing */ + dm270fb_display_disable(fbinfo); + } + +#if 0 + if (!dm270fbpar->cfg.nohwcursor) + dm270fb_hwcursor_init(fbinfo); +#endif + + fbinfo->node = -1; + if (dm270fbpar->cfg.noaccel) { + fbinfo->flags = FBINFO_DEFAULT; + } else { + fbinfo->flags = (FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN); + } + fbinfo->fbops = &dm270fb_ops; + fbinfo->currcon = -1; + + /* + * If mode_option wasn't given at boot, assume all the boot + * option timing parameters were specified individually, in + * which case we do not need to call fb_find_mode as it has + * already been copied from the boot options above. + */ +#if 0 + if (dm270fbpar->cfg.mode_option) { + struct fb_videomode* modedb, *defmode; + int dbsize = dm270fb_get_mode(fbinfo, DM270FB_DEFAULT_XRES, DM270FB_DEFAULT_YRES, &modedb, &defmode); + + /* first try the generic modedb */ + if (!fb_find_mode(&fbinfo->var, fbinfo, dm270fbpar->cfg.mode_option, + NULL, 0, NULL, fbinfo->var.bits_per_pixel)) { + WPRINTK("mode %s failed, trying dm270 modedb\n", + dm270fbpar->cfg.mode_option); + /* didn't work in generic modedb, try ours */ + if (!fb_find_mode(&fbinfo->var, fbinfo, + dm270fbpar->cfg.mode_option, modedb, dbsize, + defmode, fbinfo->var.bits_per_pixel)) { + WPRINTK("mode %s failed dm270 modedb too, sorry\n", + dm270fbpar->cfg.mode_option); + retval = -ENXIO; + goto ret_unmap_fbuf; + } + } + + fbinfo->var.xres_virtual = dm270fb_bootvar.xres_virtual ? + dm270fb_bootvar.xres_virtual : fbinfo->var.xres; + fbinfo->var.yres_virtual = dm270fb_bootvar.yres_virtual ? + dm270fb_bootvar.yres_virtual : fbinfo->var.yres; + } +#endif + + if ((retval = fb_alloc_cmap(&fbinfo->cmap, DM270FB_NR_PALETTE, 0))) { + WPRINTK("error %d allocating cmap\n", retval); + goto ret_unmap_fbuf; + } + + if (fbinfo->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { + fb_copy_cmap(&dm270fb_romclut_cmap, &fbinfo->cmap); + } + + return 0; + +ret_unmap_fbuf: + if (!dm270fbpar->cfg.noinit) { + dm270fb_unmap_graphics_memory(fbinfo); + } + fbinfo->par = NULL; + +ret_free_par: + kfree(dm270fbpar); + return retval; +} + +static int __init +dm270fb_init(void) +{ + struct dm270fb_par *dm270fbpar; + int retval = -1; + +#ifndef MODULE + if (fb_get_options("dm270fb", &dm270fb_options)) + return -ENODEV; +#endif + dm270fb_setup(dm270fb_options); + + if ((retval = dm270fb_init_fbinfo(&dm270fbinfo[0], DM270FB_NAME))) { + printk(KERN_ERR "dm270fb: error %d initializing framebuffer\n", + retval); + goto ret_failed; + } + + dm270fbpar = (struct dm270fb_par *)dm270fbinfo[0].par; + if (!dm270fbpar->cfg.noinit) { + if ((retval = dm270fb_set_par(&dm270fbinfo[0]))) { + printk(KERN_ERR "dm270fb: error %d initializing hardware\n", + retval); + goto ret_free_resource; + } + dm270fb_display_enable(&dm270fbinfo[0]); + } + + if ((retval = register_framebuffer(&dm270fbinfo[0])) < 0) { + printk(KERN_ERR "dm270fb: error %d registering framebuffer\n", + retval); + goto ret_free_resource; + } + + printk("fb%d: %s frame buffer device\n", + dm270fbinfo[0].node, dm270fbinfo[0].fix.id); + return 0; + +ret_free_resource: + if (!dm270fbpar->cfg.noinit) { + dm270fb_unmap_graphics_memory(&dm270fbinfo[0]); + } + if (dm270fbinfo[0].par) { + kfree(dm270fbinfo[0].par); + dm270fbinfo[0].par = NULL; + } + +ret_failed: + return retval; +} + +static void __exit +dm270fb_exit(void) +{ + struct dm270fb_par *dm270fbpar = (struct dm270fb_par *)dm270fbinfo[0].par; + int retval; + + if ((retval = unregister_framebuffer(&dm270fbinfo[0]))) { + WPRINTK("error %d unregistering framebuffer\n", retval); + } + fb_dealloc_cmap(&dm270fbinfo[0].cmap); + if (!dm270fbpar->cfg.noinit) { + dm270fb_unmap_graphics_memory(&dm270fbinfo[0]); + } + if (dm270fbinfo[0].par) { + kfree(dm270fbinfo[0].par); + dm270fbinfo[0].par = NULL; + } +} + +module_init(dm270fb_init); +module_exit(dm270fb_exit); + +MODULE_AUTHOR("Chee Tim Loh "); +MODULE_DESCRIPTION("TI TMS320DM270 on-chip OSD framebuffer driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(dm270fb_options, "s"); +MODULE_PARM_DESC(dm270fb_options, "Options to pass to dm270fb"); diff --git a/drivers/video/dm270fb.h b/drivers/video/dm270fb.h new file mode 100644 index 00000000..1de324c6 --- /dev/null +++ b/drivers/video/dm270fb.h @@ -0,0 +1,149 @@ +/*********************************************************************** + * drivers/video/dm270fb.h + * + * TI TMS320DM270 Frame Buffer Driver + * + * Derived from driver/video/sa1100fb.h + * + * Copyright (C) 2004 InnoMedia Pte Ltd. All rights reserved. + * cheetim_loh@innomedia.com.sg + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + ***********************************************************************/ + +#define DM270FB_DEBUG + +#define DM270FB_NR_FB 1 + +/* maximum length of fb_fix_screeninfo.id is 15 characters */ +#define DM270FB_NAME "DM270FB" + +#define DISP_TYPE_COMP 0 +#define DISP_TYPE_LCD 1 +#define DISP_TYPE_TFT 2 +#define DISP_TYPE_CRT 3 +#define DISP_TYPE_EPSON 4 +#define DISP_TYPE_CASIO 5 + +#define VID_FMT_NTSC 0 +#define VID_FMT_PAL 1 + +#define FB_ACCEL_DM270 FB_ACCEL_NONE + +#define DM270FB_NR_PALETTE 256 + +#define DM270FB_XRES_MIN 320 +#define DM270FB_YRES_MIN 200 +#define DM270FB_XRES_MAX 1024 +#define DM270FB_YRES_MAX 768 +#define DM270FB_BPP_MAX 8 + +#define DM270FB_DEFAULT_DISPTYPE DISP_TYPE_COMP +#define DM270FB_DEFAULT_VIDFMT VID_FMT_NTSC +#define DM270FB_DEFAULT_SYNC FB_SYNC_COMP_HIGH_ACT +#define DM270FB_DEFAULT_VMODE FB_VMODE_INTERLACED +#define DM270FB_DEFAULT_XRES 640 +#define DM270FB_DEFAULT_YRES 480 +#define DM270FB_DEFAULT_BPP 8 +#define DM270FB_DEFAULT_PIXCLOCK 0 +#define DM270FB_DEFAULT_LEFT_MARGIN 0 +#define DM270FB_DEFAULT_RIGHT_MARGIN 0 +#define DM270FB_DEFAULT_UPPER_MARGIN 0 +#define DM270FB_DEFAULT_LOWER_MARGIN 0 +#define DM270FB_DEFAULT_HSYNC_LEN 0 +#define DM270FB_DEFAULT_VSYNC_LEN 0 + +#define DM270FB_OSD_BASEPX_NTSC (120 + 32) +#define DM270FB_OSD_BASEPY_NTSC 18 +#define DM270FB_OSD_BASEPX_PAL (144 + 32) +#define DM270FB_OSD_BASEPY_PAL 22 + +struct dm270fb_cfg { + int noaccel; + int nopan; + int nowrap; + int nohwcursor; + int noinit; + int cmap_inverse; + int cmap_static; + int disp_type; + int vidout_std; + char fontname[40]; /* follow length of fb_info.fontname */ + char *mode_option; +}; + +struct dm270fb_regaddr { + /* address dependent on bmpwin0 or bmpwin1 */ + unsigned int bmpwinmd; + unsigned int bmpwinofst; + unsigned int bmpwinadl; + unsigned int bmpwinxp; + unsigned int bmpwinyp; + unsigned int bmpwinxl; + unsigned int bmpwinyl; + unsigned int wbmp; +}; + +struct dm270fb_regval { + unsigned short vid01; + unsigned short vid02; + unsigned short bmpwinmd; + unsigned short rectcur; + unsigned short bmpwinofst; + unsigned short bmpwinxp; + unsigned short bmpwinyp; + unsigned short bmpwinxl; + unsigned short bmpwinyl; +}; + +struct dm270fb_cursor { + int type; + int state; + int w; + int h; + int u; + int x; + int y; + int redraw; + unsigned long enable; + unsigned long disable; + struct timer_list timer; + spinlock_t lock; +}; + +struct dm270fb_par { + struct dm270fb_cfg cfg; + struct dm270fb_regaddr regaddr; + struct dm270fb_regval regval; + struct dm270fb_cursor cursor; +}; + +/* + * Debug macros + */ +#ifdef DM270FB_DEBUG +# define WPRINTK(fmt, args...) printk(KERN_WARNING "dm270fb: %s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "dm270fb: %s: " fmt, __FUNCTION__ , ## args) +#else +# define WPRINTK(fmt, args...) +# define DPRINTK(fmt, args...) +#endif diff --git a/drivers/video/m532xfb.c b/drivers/video/m532xfb.c new file mode 100644 index 00000000..45c863b8 --- /dev/null +++ b/drivers/video/m532xfb.c @@ -0,0 +1,615 @@ +/* + * linux/drivers/video/m532xfb.c -- Coldfire MCF5329 frame buffer driver + * + * Copyright (c) 2006, emlix, Thomas Brinker + * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com + * Copyright Freescale Semiconductor, Inc 2006 + * + * 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. + * + * Modified for Coldfire M5329 frame buffer by yaroslav.vinogradov@freescale.com + * Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com) + * Created 28 Dec 1997 by Geert Uytterhoeven + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FB_HWAIT1 0 +#define FB_HWIDTH 1 +#define FB_HWAIT2 2 +#define FB_VWAIT1 3 +#define FB_VWIDTH 4 +#define FB_VWAIT2 5 + +static u32 fb_wait_params[][6] = { +/* HWAIT1, HWIDTH, HWAIT2, VWAIT1, VWIDTH, VWAIT2 */ +/* 640x480 */ {48, 14, 102, 32, 1, 35}, +/* 800x600 */ {110, 59, 85, 42, 3, 24}, +/* 240x320 */ {85, 10, 75, 32, 10, 10} +}; + +#if defined(CONFIG_LCD_640x480) +#define MODE_OPTION "640x480@60" +#define MODE_BPP 32 +#define MODE_WIDTH 640 +#define MODE_HEIGHT 480 +#define MODE_VPW MODE_WIDTH +#define FB_WAIT_PARAMS(p) (fb_wait_params[0][(p)]) +#define PIX_CLK_DIV 12 +#define LCDC_LDCR_VALUE (MCF_LCDC_LDCR_TM(8) | MCF_LCDC_LDCR_HM(4)) + +#elif defined(CONFIG_LCD_800x600) +#define MODE_OPTION "800x600@60" +#define MODE_BPP 32 /* Default is 32 bits, 16 bits mode is also aviable */ +#define MODE_WIDTH 800 +#define MODE_HEIGHT 600 +#define MODE_VPW (MODE_WIDTH >> (MODE_BPP == 16 ? 1 : 0)) +#define FB_WAIT_PARAMS(p) (fb_wait_params[1][(p)]) +#define PIX_CLK_DIV 3 +#define LCDC_LDCR_VALUE (MCF_LCDC_LDCR_TM(8) | MCF_LCDC_LDCR_HM(4)) + +#elif defined(CONFIG_LCD_240x320) +#define MODE_OPTION "240x320@60" +#define MODE_BPP 32 +#define MODE_WIDTH 240 +#define MODE_HEIGHT 320 +#define MODE_VPW (MODE_WIDTH >> (MODE_BPP == 16 ? 1 : 0)) +#define FB_WAIT_PARAMS(p) (fb_wait_params[2][(p)]) +#define PIX_CLK_DIV 12 +#define LCDC_LDCR_VALUE (MCF_LCDC_LDCR_TM(4) | MCF_LCDC_LDCR_HM(8) | MCF_LCDC_LDCR_BURST) + +#else +#error "LCD display resolution is not specified!" +#endif + +extern int soft_cursor(struct fb_info* info, struct fb_cursor* cursor); + +/* + * This structure defines the hardware state of the graphics card. Normally + * you place this in a header file in linux/include/video. This file usually + * also includes register information. That allows other driver subsystems + * and userland applications the ability to use the same header file to + * avoid duplicate work and easy porting of software. + */ +struct m532x_par { + char mode_option[40]; +/* ... */ + unsigned dump; +}; + +/* + * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo + * if we don't use modedb. If we do use modedb see xxxfb_init how to use it + * to get a fb_var_screeninfo. Otherwise define a default var as well. + */ +static struct fb_fix_screeninfo m532xfb_fix = { + .id = "M532x FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + + /* + * Modern graphical hardware not only supports pipelines but some + * also support multiple monitors where each display can have its + * its own unique data. In this case each display could be + * represented by a separate framebuffer device thus a separate + * struct fb_info. Now the struct xxx_par represents the graphics + * hardware state thus only one exist per card. In this case the + * struct xxx_par for each graphics card would be shared between + * every struct fb_info that represents a framebuffer on that card. + * This allows when one display changes it video resolution (info->var) + * the other displays know instantly. Each display can always be + * aware of the entire hardware state that affects it because they share + * the same xxx_par struct. The other side of the coin is multiple + * graphics cards that pass data around until it is finally displayed + * on one monitor. Such examples are the voodoo 1 cards and high end + * NUMA graphics servers. For this case we have a bunch of pars, each + * one that represents a graphics state, that belong to one struct + * fb_info. Their you would want to have *par point to a array of device + * states and have each struct fb_ops function deal with all those + * states. I hope this covers every possible hardware design. If not + * feel free to send your ideas at jsimmons@users.sf.net + */ + + /* + * If your driver supports multiple boards or it supports multiple + * framebuffers, you should make these arrays, or allocate them + * dynamically (using kmalloc()). + */ +static struct fb_info info; + + /* + * Each one represents the state of the hardware. Most hardware have + * just one hardware state. These here represent the default state(s). + */ + +#define DUMP_OPTIONS 0x0 /* nothing */ +//#define DUMP_OPTIONS 0xffffffff /* everything */ + +static struct m532x_par current_par = { + .mode_option = MODE_OPTION, + .dump = DUMP_OPTIONS, +}; + +static u32 pseudo_palette[256]; + +int m532xfb_init(void); +int m532xfb_setup(char*); + +/* ----- DUMP start ----- */ + +void m532xfb_dump_var(struct fb_info *info) +{ + printk("*** FB var: ***\n"); + printk("resolution: %d x %d\n", info->var.xres, info->var.yres); + printk("virtual: %d x %d\n", info->var.xres_virtual, info->var.yres_virtual); + printk("offsets: %d x %d\n", info->var.xoffset, info->var.yoffset); + printk("bpp: %d\n", info->var.bits_per_pixel); + printk("grey: %d\n", info->var.grayscale); + + printk("red: off: %d len %d msb %d\n", info->var.red.offset, info->var.red.length, info->var.red.msb_right); + printk("green: off: %d len %d msb %d\n", info->var.green.offset, info->var.green.length, info->var.green.msb_right); + printk("blue: off: %d len %d msb %d\n", info->var.blue.offset, info->var.blue.length, info->var.blue.msb_right); + printk("transp:off: %d len %d msb %d\n", info->var.transp.offset, info->var.transp.length, info->var.transp.msb_right); + + printk("pixelformat:%d\n", info->var.nonstd); + printk("activate: %d\n", info->var.activate); + printk("dimension: %d x %d\n", info->var.height, info->var.width); + + printk("pixclock: %lu\n", PICOS2KHZ(info->var.pixclock)); + printk("margins: %d - %d - %d - %d\n", info->var.left_margin, info->var.right_margin, info->var.upper_margin, info->var.lower_margin); + printk("synclen: %d - %d\n", info->var.hsync_len, info->var.vsync_len); + printk("sync: %d\n", info->var.sync); + printk("vmode: %d\n", info->var.vmode); + printk("rotate: %d\n\n", info->var.rotate); +} + +void m532xfb_dump_fix(struct fb_info *info) +{ + printk("*** FB fix: ***\n"); + printk("id %s\n", info->fix.id); + printk("smem_start 0x%08lx\n", info->fix.smem_start); + printk("smem_len %d\n", info->fix.smem_len); + printk("type: %d\n", info->fix.type); + printk("type_aux: %d\n", info->fix.type_aux); + printk("visual: %d\n", info->fix.visual); + printk("xpanstep %d\n", info->fix.xpanstep); + printk("ypanstep %d\n", info->fix.ypanstep); + printk("ywrapstep %d\n", info->fix.ywrapstep); + printk("line_length %d\n", info->fix.line_length); + printk("accel %d\n\n", info->fix.accel); +} + +void m532xfb_dump_par(struct fb_info *info) +{ + struct m532x_par *par = (struct m532x_par *) info->par; + printk("*** FB par: ***\n"); + printk("dump: %d\n\n", par->dump); +} + +void m532xfb_dump_colors(void) +{ +} + +void m532xfb_dump_info(struct fb_info *info) +{ + int dump = ((struct m532x_par *) info->par)->dump; + if (!dump) return; + printk("-------------------------------------------------------------------\n"); + printk("*** FB info DUMP ***\n"); + printk("node: %d\n", info->node); + printk("flags: %d\n\n", info->flags); + printk("screenbase: 0x%p\n", info->screen_base); + printk("screen_size: 0x%08lx\n", info->screen_size); + printk("state: %d\n\n", info->state); + + if (dump & 0x02) + m532xfb_dump_fix(info); + if (dump & 0x04) + m532xfb_dump_var(info); + if (dump & 0x08) + m532xfb_dump_par(info); + if (dump & 0x10) + m532xfb_dump_colors(); + + printk("*** LCD-Registers ***\n"); + printk("MCF_LCDC_LSSAR 0x%08lx\n",MCF_LCDC_LSSAR); + printk("MCF_LCDC_LSR 0x%08lx\n",MCF_LCDC_LSR); + printk("MCF_LCDC_LVPWR 0x%08lx\n",MCF_LCDC_LVPWR); + printk("MCF_LCDC_LCPR 0x%08lx\n",MCF_LCDC_LCPR); + printk("MCF_LCDC_LCWHBR 0x%08lx\n",MCF_LCDC_LCWHBR); + printk("MCF_LCDC_LCCMR 0x%08lx\n",MCF_LCDC_LCCMR); + printk("MCF_LCDC_LPCR 0x%08lx\n",MCF_LCDC_LPCR); + printk("MCF_LCDC_LHCR 0x%08lx\n",MCF_LCDC_LHCR); + printk("MCF_LCDC_LVCR 0x%08lx\n",MCF_LCDC_LVCR); + printk("MCF_LCDC_LPOR 0x%08lx\n",MCF_LCDC_LPOR); + printk("MCF_LCDC_LSCR 0x%08lx\n",MCF_LCDC_LSCR); + printk("MCF_LCDC_LPCCR 0x%08lx\n",MCF_LCDC_LPCCR); + printk("MCF_LCDC_LDCR 0x%08lx\n",MCF_LCDC_LDCR); + printk("MCF_LCDC_LRMCR 0x%08lx\n",MCF_LCDC_LRMCR); + printk("MCF_LCDC_LICR 0x%08lx\n",MCF_LCDC_LICR); + printk("MCF_LCDC_LIER 0x%08lx\n",MCF_LCDC_LIER); + printk("MCF_LCDC_LISR 0x%08lx\n",MCF_LCDC_LISR); + printk("MCF_LCDC_LGWSAR 0x%08lx\n",MCF_LCDC_LGWSAR); + printk("MCF_LCDC_LGWSR 0x%08lx\n",MCF_LCDC_LGWSR); + printk("MCF_LCDC_LGWVPWR 0x%08lx\n",MCF_LCDC_LGWVPWR); + printk("MCF_LCDC_LGWPOR 0x%08lx\n",MCF_LCDC_LGWPOR); + printk("MCF_LCDC_LGWPR 0x%08lx\n",MCF_LCDC_LGWPR); + printk("MCF_LCDC_LGWCR 0x%08lx\n",MCF_LCDC_LGWCR); + printk("MCF_LCDC_LGWDCR 0x%08lx\n",MCF_LCDC_LGWDCR); + printk("MCF_LCDC_BPLUT_BASE 0x%08lx\n",MCF_LCDC_BPLUT_BASE); + printk("MCF_LCDC_GWLUT_BASE 0x%08lx\n",MCF_LCDC_GWLUT_BASE); + printk("-------------------------------------------------------------------\n"); +} + +/* ----- DUMP end ----- */ + +/** + * xxxfb_setcolreg - Optional function. Sets a color register. + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported, the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Things to take into consideration are how many color registers, if + * any, are supported with the current color visual. With truecolor mode + * no color palettes are supported. Here a pseudo palette is created + * which we store the value in pseudo_palette in struct fb_info. For + * pseudocolor mode we have a limited color palette. To deal with this + * we can program what color is displayed for a particular pixel value. + * DirectColor is similar in that we can program each color field. If + * we have a static colormap we don't need to implement this function. + * + * Returns negative errno on error, or zero on success. + */ +static int m532xfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + const struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return -EINVAL; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of DAC + * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = DAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * DAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use RAMDAC (usually has 3 of them). + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + /* example here assumes 8 bit DAC. Might be different + * for your hardware */ + red = CNVT_TOHW(red, 8); + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return -EINVAL; + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + switch (info->var.bits_per_pixel) { + case 8: + /* Yes some hand held devices have this. */ + ((u8*)(info->pseudo_palette))[regno] = v; + break; + case 16: + ((u16*)(info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32*)(info->pseudo_palette))[regno] = v; + break; + } + return 0; + } + /* ... */ +printk("do something with color palette!\n"); + return 0; +} +/* ------------------------------------------------------------------------- */ + +/* + * Frame buffer operations + */ + +static struct fb_ops m532xfb_ops = { + .owner = THIS_MODULE, + .fb_fillrect = cfb_fillrect, /* Needed !!! */ + .fb_copyarea = cfb_copyarea, /* Needed !!! */ + .fb_imageblit = cfb_imageblit, /* Needed !!! */ + .fb_cursor = soft_cursor, /* Needed !!! */ +}; + +/* + * Initialization + */ +int __init m532xfb_init(void) +{ + int cmap_len=256, retval; + char* mode_option=NULL; + + /* + * For kernel boot options (in 'video=xxxfb:' format) + */ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("m532xfb", &option)) { + printk("No fb on command line specified\n"); + return -ENODEV; + } + m532xfb_setup(option); +#endif + + printk("Initing M532x Framebuffer\n"); + + info.fbops = &m532xfb_ops; + info.fix = m532xfb_fix; + info.pseudo_palette = pseudo_palette; + + /* + * Set up flags to indicate what sort of acceleration your + * driver can provide (pan/wrap/copyarea/etc.) and whether it + * is a module -- see FBINFO_* in include/linux/fb.h + */ + info.flags = FBINFO_DEFAULT + FBINFO_HWACCEL_DISABLED; + info.par = ¤t_par; + + /* + * This should give a reasonable default video mode. The following is + * done when we can set a video mode. + */ + if (!mode_option) + mode_option = MODE_OPTION; + + retval = fb_find_mode(&info.var, &info, mode_option, NULL, 0, NULL, MODE_BPP); + + if (!retval || retval == 4) + return -EINVAL; + + info.screen_size = (info.var.xres * info.var.yres * info.var.bits_per_pixel) / 8; + info.var.xres_virtual = info.var.xres; + info.var.yres_virtual = info.var.yres; + +#if MODE_BPP == 32 + info.var.red.offset = 18; + info.var.red.length = 6; + info.var.red.msb_right = 0; + + info.var.green.offset = 10; + info.var.green.length = 6; + info.var.green.msb_right = 0; + + info.var.blue.offset = 2; + info.var.blue.length = 6; + info.var.blue.msb_right = 0; + + info.var.transp.offset = 0; + info.var.transp.length = 0; + info.var.transp.msb_right = 0; +#else + info.var.red.offset = 11; + info.var.red.length = 5; + + info.var.green.offset = 5; + info.var.green.length = 6; + + info.var.blue.offset = 0; + info.var.blue.length = 5; +#endif + + /* + * Here we set the screen_base to the virtual memory address + * for the framebuffer. Usually we obtain the resource address + * from the bus layer and then translate it to virtual memory + * space via ioremap. Consult ioport.h. + */ + info.screen_base = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(info.screen_size)); + if (!info.screen_base) { + printk("Unable to allocate %d PAGEs(%ld Bytes) fb memory\n",get_order(info.screen_size),info.screen_size); + return -ENOMEM; + } + + info.fix.smem_start = virt_to_phys((void *)info.screen_base); + info.fix.smem_len = info.screen_size; + info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8; + + /* + * Set page reserved so that mmap will work. This is necessary + * since we'll be remapping normal memory. + */ + { + unsigned char * page; + for (page = info.screen_base; + (unsigned long)page < (PAGE_ALIGN((unsigned long)info.screen_base + info.screen_size)); + page += PAGE_SIZE) + { + SetPageReserved(virt_to_page(page)); + } + } + memset((void *)info.screen_base, 0, info.screen_size); + + /* set gpios */ + MCF_GPIO_PAR_LCDDATA = 0xff; /* switch all to display */ + MCF_GPIO_PAR_LCDCTL = 0x1ff; + + /* burst mode */ + MCF_SCM_BCR = 0x3ff; + + MCF_LCDC_LSSAR = (unsigned int)info.screen_base; + MCF_LCDC_LSR = MCF_LCDC_LSR_XMAX(MODE_WIDTH/16) | MCF_LCDC_LSR_YMAX(MODE_HEIGHT); + MCF_LCDC_LVPWR = MCF_LCDC_LVPWR_VPW(MODE_VPW); + +#if defined(CONFIG_LCD_640x480) + MCF_LCDC_LPCR = MCF_LCDC_LPCR_TFT + | MCF_LCDC_LPCR_COLOR + | MCF_LCDC_LPCR_BPIX_18bpp + | MCF_LCDC_LPCR_FLM + | MCF_LCDC_LPCR_LPPOL + | MCF_LCDC_LPCR_OEPOL + | MCF_LCDC_LPCR_CLKPOL + | MCF_LCDC_LPCR_SCLKSEL + | MCF_LCDC_LPCR_ACDSEL + | MCF_LCDC_LPCR_ENDSEL + | MCF_LCDC_LPCR_PCD(PIX_CLK_DIV); +#elif defined(CONFIG_LCD_800x600) + MCF_LCDC_LPCR = MCF_LCDC_LPCR_MODE_TFT +#if MODE_BPP == 32 + | MCF_LCDC_LPCR_BPIX_18bpp +#else + | MCF_LCDC_LPCR_BPIX_16bpp +#endif + | MCF_LCDC_LPCR_FLM + | MCF_LCDC_LPCR_LPPOL + | MCF_LCDC_LPCR_CLKPOL + | MCF_LCDC_LPCR_OEPOL + | MCF_LCDC_LPCR_ACDSEL + | MCF_LCDC_LPCR_SCLKSEL + | MCF_LCDC_LPCR_ENDSEL + | MCF_LCDC_LPCR_PCD(PIX_CLK_DIV); +#elif defined(CONFIG_LCD_240x320) + MCF_LCDC_LPCR = MCF_LCDC_LPCR_TFT + | MCF_LCDC_LPCR_COLOR + | MCF_LCDC_LPCR_BPIX_18bpp + | MCF_LCDC_LPCR_FLM + | MCF_LCDC_LPCR_LPPOL + | MCF_LCDC_LPCR_OEPOL + | MCF_LCDC_LPCR_CLKPOL + | MCF_LCDC_LPCR_SCLKSEL + | MCF_LCDC_LPCR_ACDSEL + | MCF_LCDC_LPCR_ENDSEL + | MCF_LCDC_LPCR_PCD(PIX_CLK_DIV); +#endif + + MCF_LCDC_LHCR = MCF_LCDC_LHCR_H_WIDTH(FB_WAIT_PARAMS(FB_HWIDTH)) + | MCF_LCDC_LHCR_H_WAIT_1(FB_WAIT_PARAMS(FB_HWAIT1)) + | MCF_LCDC_LHCR_H_WAIT_2(FB_WAIT_PARAMS(FB_HWAIT2)); + + MCF_LCDC_LVCR = MCF_LCDC_LVCR_V_WIDTH(FB_WAIT_PARAMS(FB_VWIDTH)) + | MCF_LCDC_LVCR_V_WAIT_1(FB_WAIT_PARAMS(FB_VWAIT1)) + | MCF_LCDC_LVCR_V_WAIT_2(FB_WAIT_PARAMS(FB_VWAIT2)); + + MCF_LCDC_LPOR = MCF_LCDC_LPOR_POS(0); + MCF_LCDC_LDCR = LCDC_LDCR_VALUE; + + /* connect ldc controller to clock */ + MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LCD_CHEN; + + /* This has to been done !!! */ + fb_alloc_cmap(&info.cmap, cmap_len, 0); + + /* + * The following is done in the case of having hardware with a static + * mode. If we are setting the mode ourselves we don't call this. + */ + if (register_framebuffer(&info) < 0) + return -EINVAL; + printk(KERN_INFO "fb%d: %s frame buffer device\n", info.node, info.fix.id); + + m532xfb_dump_info(&info); + + return 0; +} + +/* +* Cleanup +*/ +static void __exit m532xfb_cleanup(void) +{ + /* + * If your driver supports multiple boards, you should unregister and + * clean up all instances. + */ + unregister_framebuffer(&info); + fb_dealloc_cmap(&info.cmap); + /* ... */ +} + +/* +* Setup +*/ + +/* + * Only necessary if your driver takes special options, + * otherwise we fall back on the generic fb_setup(). + */ +int __init m532xfb_setup(char *options) +{ + /* Parse user speficied options (`video=xxxfb:') */ + return 0; +} +/* ------------------------------------------------------------------------- */ +/* +* Modularization +*/ +module_init(m532xfb_init); +module_exit(m532xfb_cleanup); + +MODULE_AUTHOR("Thomas Brinker "); +MODULE_DESCRIPTION("MCF532x Framebuffer"); +MODULE_LICENSE("GPL"); diff --git a/fs/Kconfig b/fs/Kconfig index 7b1511d5..916480c4 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -634,6 +634,21 @@ config FUSE_FS If you want to develop a userspace FS, or if you want to use a filesystem based on FUSE, answer Y or M. +config DIRECTIO + bool "Direct I/O support" if EMBEDDED + default y + help + This option enables applications to perform uncached I/O on files + using the O_DIRECT open() flag. When O_DIRECT is set for a file, + its data is not cached in the system's page cache. Data is moved + to and from user-level application buffers directly. + + In addition to enabling this option, the file system must also + support direct I/O. + + If unsure, say Y. Saying N here causes open() to return EINVAL if + a file is opened with the O_DIRECT flag. + config GENERIC_ACL bool select FS_POSIX_ACL @@ -1020,7 +1035,7 @@ config HUGETLB_PAGE def_bool HUGETLBFS config RAMFS - bool + bool "Support RAM file system" default y ---help--- Ramfs is a file system which keeps all files in RAM. It allows @@ -1407,6 +1422,83 @@ config CRAMFS If unsure, say N. +config SQUASHFS + tristate "SquashFS 2.2 - Squashed file system support" + select ZLIB_INFLATE + help + Saying Y here includes support for SquashFS 2.2 (Compressed Read-Only File + System). Squashfs is a highly compressed read-only filesystem for Linux. + It uses zlib compression to compress both files, inodes and directories. + Inodes in the system are very small and all blocks are packed to minimise + data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. + + Squashfs is intended for general read-only filesystem use, for archival + use (i.e. in cases where a .tar.gz file may be used), and in embedded + systems where low overhead is needed. Further information and filesystem tools + are available from http://squashfs.sourceforge.net. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called squashfs. Note that the root file system (the one + containing the directory /) cannot be compiled as a module. + + If unsure, say N. + +config SQUASHFS_CRAMFS_MAGIC + bool "Image has a dummy cramfs header (8 bytes)" + depends on SQUASHFS + default n + help + The squashfs image has a dummy cramfs header so that old boot + loaders and initrd tools will know it's size/type. + +config SQUASHFS_LZMA + bool "Use LZMA for better compression" + depends on SQUASHFS + default n + help + Use LZMA compression (p7zip) for even better space savings. + +config SQUASHFS_EMBEDDED + bool "Additional options for memory-constrained systems" + depends on SQUASHFS + default n + help + Saying Y here allows you to specify cache sizes and how Squashfs + allocates memory. This is only intended for memory constrained + systems. + + If unsure, say N. + +config SQUASHFS_FRAGMENT_CACHE_SIZE + int "Number of fragments cached" if SQUASHFS_EMBEDDED + depends on SQUASHFS + default "3" + help + By default SquashFS caches the last 3 fragments read from + the filesystem. Increasing this amount may mean SquashFS + has to re-read fragments less often from disk, at the expense + of extra system memory. Decreasing this amount will mean + SquashFS uses less memory at the expense of extra reads from disk. + + Note there must be at least one cached fragment. Anything + much more than three will probably not make much difference. + +config SQUASHFS_VMALLOC + bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED + depends on SQUASHFS + default n + help + By default SquashFS uses kmalloc to obtain fragment cache memory. + Kmalloc memory is the standard kernel allocator, but it can fail + on memory constrained systems. Because of the way Vmalloc works, + Vmalloc can succeed when kmalloc fails. Specifying this option + will make SquashFS always use Vmalloc to allocate the + fragment cache memory. + + If unsure, say N. + config VXFS_FS tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" depends on BLOCK @@ -1635,7 +1727,7 @@ config NFS_V4 config NFS_DIRECTIO bool "Allow direct I/O on NFS files" - depends on NFS_FS + depends on NFS_FS && DIRECTIO help This option enables applications to perform uncached I/O on files in NFS file systems using the O_DIRECT open() flag. When O_DIRECT @@ -2098,5 +2190,18 @@ endif source "fs/nls/Kconfig" source "fs/dlm/Kconfig" +menu "Debug" + +config COREDUMP_PRINTK + bool "Coredump printk support (for embedded systems)" + help + If you say Y here, you will get printk/console output whenever + an application crashes. On Embedded systems with RO filesystems + and little storage, coredumps are not practical, this allows + problems to be noticed and fixed. + If unsure, say N. + +endmenu + endmenu diff --git a/fs/Makefile b/fs/Makefile index 9a5ce932..3c23112d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -57,6 +57,9 @@ obj-$(CONFIG_CONFIGFS_FS) += configfs/ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o + +obj-$(CONFIG_DIRECTIO) += direct-io.o + obj-$(CONFIG_DLM) += dlm/ # Do not add any filesystems before this line @@ -67,6 +70,7 @@ obj-$(CONFIG_JBD) += jbd/ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ +obj-$(CONFIG_SQUASHFS) += squashfs/ obj-$(CONFIG_RAMFS) += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index a62fd401..6ea5f688 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -290,7 +290,7 @@ out_free_buf: kfree(buf); out_free: kfree(strm.workspace); -out: +//out: // mask by Victor Yu. 03-14-2007 return retval; } @@ -419,7 +419,7 @@ static int load_flat_file(struct linux_binprm * bprm, unsigned long textpos = 0, datapos = 0, result; unsigned long realdatastart = 0; unsigned long text_len, data_len, bss_len, stack_len, flags; - unsigned long memp = 0; /* for finding the brk area */ + unsigned long len, reallen, memp = 0; unsigned long extra, rlim; unsigned long *reloc = 0, *rp; struct inode *inode; @@ -540,10 +540,20 @@ static int load_flat_file(struct linux_binprm * bprm, goto err; } + len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); down_write(¤t->mm->mmap_sem); - realdatastart = do_mmap(0, 0, data_len + extra + - MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); + realdatastart = do_mmap(0, 0, len, + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); + /* Remap to use all availabe slack region space */ +#if 1 // mask by Victor Yu. 03-15-2007, I don't know why ? It will let the system dead. + if (realdatastart && (realdatastart < (unsigned long)-4096)) { + reallen = ksize(realdatastart); + if (reallen > len) { + realdatastart = do_mremap(realdatastart, len, + reallen, MREMAP_FIXED, realdatastart); + } + } +#endif up_write(¤t->mm->mmap_sem); if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { @@ -584,11 +594,22 @@ static int load_flat_file(struct linux_binprm * bprm, } else { + len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); down_write(¤t->mm->mmap_sem); - textpos = do_mmap(0, 0, text_len + data_len + extra + - MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); + textpos = do_mmap(0, 0, len, + PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); + /* Remap to use all availabe slack region space */ +#if 1 // mask by Victor Yu. 03-15-2007, I don't know why ? It will let the system dead. + if (textpos && (textpos < (unsigned long) -4096)) { + reallen = ksize(textpos); + if (reallen > len) { + textpos = do_mremap(textpos, len, reallen, + MREMAP_FIXED, textpos); + } + } +#endif up_write(¤t->mm->mmap_sem); + if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos) textpos = (unsigned long) -ENOMEM; diff --git a/fs/block_dev.c b/fs/block_dev.c index 36c0e7af..9801fed9 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -129,6 +129,7 @@ blkdev_get_block(struct inode *inode, sector_t iblock, return 0; } +#ifdef CONFIG_DIRECTIO static int blkdev_get_blocks(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create) @@ -167,6 +168,7 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode), iov, offset, nr_segs, blkdev_get_blocks, NULL); } +#endif static int blkdev_writepage(struct page *page, struct writeback_control *wbc) { @@ -276,7 +278,11 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) static inline void __bd_forget(struct inode *inode) { list_del_init(&inode->i_devices); +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_bdev = NULL; +#else + inode->u.i_bdev = NULL; +#endif inode->i_mapping = &inode->i_data; } @@ -376,7 +382,11 @@ struct block_device *bdget(dev_t dev) bdev->bd_invalidated = 0; inode->i_mode = S_IFBLK; inode->i_rdev = dev; +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_bdev = bdev; +#else + inode->u.i_bdev = bdev; +#endif inode->i_data.a_ops = &def_blk_aops; mapping_set_gfp_mask(&inode->i_data, GFP_USER); inode->i_data.backing_dev_info = &default_backing_dev_info; @@ -416,7 +426,11 @@ static struct block_device *bd_acquire(struct inode *inode) struct block_device *bdev; spin_lock(&bdev_lock); +#if 0 // mask by Victor Yu. 02-12-2007 bdev = inode->i_bdev; +#else + bdev = inode->u.i_bdev; +#endif if (bdev) { atomic_inc(&bdev->bd_inode->i_count); spin_unlock(&bdev_lock); @@ -427,7 +441,11 @@ static struct block_device *bd_acquire(struct inode *inode) bdev = bdget(inode->i_rdev); if (bdev) { spin_lock(&bdev_lock); +#if 0 // mask by Victor Yu. 02-12-2007 if (!inode->i_bdev) { +#else + if (!inode->u.i_bdev) { +#endif /* * We take an additional bd_inode->i_count for inode, * and it's released in clear_inode() of inode. @@ -435,7 +453,11 @@ static struct block_device *bd_acquire(struct inode *inode) * without igrab(). */ atomic_inc(&bdev->bd_inode->i_count); +#if 0 // mask by Viccctor Yu. 02-12-2007 inode->i_bdev = bdev; +#else + inode->u.i_bdev = bdev; +#endif inode->i_mapping = bdev->bd_inode->i_mapping; list_add(&inode->i_devices, &bdev->bd_inodes); } @@ -451,9 +473,17 @@ void bd_forget(struct inode *inode) struct block_device *bdev = NULL; spin_lock(&bdev_lock); +#if 0 // mask by Victor Yu. 02-12-2007 if (inode->i_bdev) { +#else + if (inode->u.i_bdev) { +#endif if (inode->i_sb != blockdev_superblock) +#if 0 // mask by Victor Yu. 02-12-2007 bdev = inode->i_bdev; +#else + bdev = inode->u.i_bdev; +#endif __bd_forget(inode); } spin_unlock(&bdev_lock); @@ -1188,7 +1218,9 @@ const struct address_space_operations def_blk_aops = { .prepare_write = blkdev_prepare_write, .commit_write = blkdev_commit_write, .writepages = generic_writepages, +#ifdef CONFIG_DIRECTIO .direct_IO = blkdev_direct_IO, +#endif }; const struct file_operations def_blk_fops = { diff --git a/fs/buffer.c b/fs/buffer.c index 35527dca..ae118008 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -288,8 +288,13 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) "block=%llu, b_blocknr=%llu\n", (unsigned long long)block, (unsigned long long)bh->b_blocknr); +#if 0 // mask by Victor Yu. 02-12-2007 printk("b_state=0x%08lx, b_size=%zu\n", bh->b_state, bh->b_size); +#else + printk("b_state=0x%08lx, b_size=%u\n", + bh->b_state, bh->b_size); +#endif printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); } out_unlock: @@ -451,7 +456,11 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate) "I/O error on %s\n", bdevname(bh->b_bdev, b)); } +#if 0 // mask by Victor Yu. 02-12-2007 set_bit(AS_EIO, &page->mapping->flags); +#else + set_bit(AS_EIO, &page->u.xx.mapping->flags); +#endif set_buffer_write_io_error(bh); clear_buffer_uptodate(bh); SetPageError(page); @@ -662,7 +671,11 @@ void write_boundary_block(struct block_device *bdev, void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) { struct address_space *mapping = inode->i_mapping; +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *buffer_mapping = bh->b_page->mapping; +#else + struct address_space *buffer_mapping = bh->b_page->u.xx.mapping; +#endif mark_buffer_dirty(bh); if (!mapping->assoc_mapping) { @@ -726,7 +739,11 @@ int __set_page_dirty_buffers(struct page *page) if (!TestSetPageDirty(page)) { write_lock_irq(&mapping->tree_lock); +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping) { /* Race with truncate? */ +#else + if (page->u.xx.mapping) { /* Race with truncate? */ +#endif if (mapping_cap_account_dirty(mapping)) __inc_zone_page_state(page, NR_FILE_DIRTY); radix_tree_tag_set(&mapping->page_tree, @@ -1169,7 +1186,11 @@ void __bforget(struct buffer_head *bh) { clear_buffer_dirty(bh); if (!list_empty(&bh->b_assoc_buffers)) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *buffer_mapping = bh->b_page->mapping; +#else + struct address_space *buffer_mapping = bh->b_page->u.xx.mapping; +#endif spin_lock(&buffer_mapping->private_lock); list_del_init(&bh->b_assoc_buffers); @@ -1510,7 +1531,11 @@ void create_empty_buffers(struct page *page, } while (bh); tail->b_this_page = head; +#if 0 // mask by Victor Yu. 02-12-2007 spin_lock(&page->mapping->private_lock); +#else + spin_lock(&page->u.xx.mapping->private_lock); +#endif if (PageUptodate(page) || PageDirty(page)) { bh = head; do { @@ -1522,7 +1547,11 @@ void create_empty_buffers(struct page *page, } while (bh != head); } attach_page_buffers(page, head); +#if 0 // mask by Victor Yu. 02-12-2007 spin_unlock(&page->mapping->private_lock); +#else + spin_unlock(&page->u.xx.mapping->private_lock); +#endif } EXPORT_SYMBOL(create_empty_buffers); @@ -1916,7 +1945,11 @@ static int __block_commit_write(struct inode *inode, struct page *page, */ int block_read_full_page(struct page *page, get_block_t *get_block) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif sector_t iblock, lblock; struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; unsigned int blocksize; @@ -2089,7 +2122,11 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size) int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, loff_t *bytes) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif struct inode *inode = mapping->host; struct page *new_page; pgoff_t pgpos; @@ -2170,7 +2207,11 @@ out: int block_prepare_write(struct page *page, unsigned from, unsigned to, get_block_t *get_block) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int err = __block_prepare_write(inode, page, from, to, get_block); if (err) ClearPageUptodate(page); @@ -2179,7 +2220,11 @@ int block_prepare_write(struct page *page, unsigned from, unsigned to, int block_commit_write(struct page *page, unsigned from, unsigned to) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif __block_commit_write(inode,page,from,to); return 0; } @@ -2187,7 +2232,11 @@ int block_commit_write(struct page *page, unsigned from, unsigned to) int generic_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; __block_commit_write(inode,page,from,to); /* @@ -2230,7 +2279,11 @@ static void end_buffer_read_nobh(struct buffer_head *bh, int uptodate) int nobh_prepare_write(struct page *page, unsigned from, unsigned to, get_block_t *get_block) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif const unsigned blkbits = inode->i_blkbits; const unsigned blocksize = 1 << blkbits; struct buffer_head map_bh; @@ -2379,7 +2432,11 @@ EXPORT_SYMBOL(nobh_prepare_write); int nobh_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; set_page_dirty(page); @@ -2399,7 +2456,11 @@ EXPORT_SYMBOL(nobh_commit_write); int nobh_writepage(struct page *page, get_block_t *get_block, struct writeback_control *wbc) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode * const inode = page->mapping->host; +#else + struct inode * const inode = page->u.xx.mapping->host; +#endif loff_t i_size = i_size_read(inode); const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; @@ -2571,7 +2632,11 @@ out: int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode * const inode = page->mapping->host; +#else + struct inode * const inode = page->u.xx.mapping->host; +#endif loff_t i_size = i_size_read(inode); const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset; @@ -2804,8 +2869,13 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free) bh = head; do { +#if 0 // mask by Victor Yu. 02-12-2007 if (buffer_write_io_error(bh) && page->mapping) set_bit(AS_EIO, &page->mapping->flags); +#else + if (buffer_write_io_error(bh) && page->u.xx.mapping) + set_bit(AS_EIO, &page->u.xx.mapping->flags); +#endif if (buffer_busy(bh)) goto failed; bh = bh->b_this_page; @@ -2827,7 +2897,11 @@ failed: int try_to_free_buffers(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space * const mapping = page->mapping; +#else + struct address_space * const mapping = page->u.xx.mapping; +#endif struct buffer_head *buffers_to_free = NULL; int ret = 0; diff --git a/fs/char_dev.c b/fs/char_dev.c index a885f46c..013257d5 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -364,7 +364,11 @@ int chrdev_open(struct inode * inode, struct file * filp) int ret = 0; spin_lock(&cdev_lock); +#if 0 // mask by Victor Yu. 02-12-2007 p = inode->i_cdev; +#else + p = inode->u.i_cdev; +#endif if (!p) { struct kobject *kobj; int idx; @@ -374,9 +378,17 @@ int chrdev_open(struct inode * inode, struct file * filp) return -ENXIO; new = container_of(kobj, struct cdev, kobj); spin_lock(&cdev_lock); +#if 0 // mask by Victor Yu. 02-12-2007 p = inode->i_cdev; +#else + p = inode->u.i_cdev; +#endif if (!p) { +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_cdev = p = new; +#else + inode->u.i_cdev = p = new; +#endif inode->i_cindex = idx; list_add(&inode->i_devices, &p->list); new = NULL; @@ -407,7 +419,11 @@ void cd_forget(struct inode *inode) { spin_lock(&cdev_lock); list_del_init(&inode->i_devices); +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_cdev = NULL; +#else + inode->u.i_cdev = NULL; +#endif spin_unlock(&cdev_lock); } @@ -418,7 +434,11 @@ static void cdev_purge(struct cdev *cdev) struct inode *inode; inode = container_of(cdev->list.next, struct inode, i_devices); list_del_init(&inode->i_devices); +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_cdev = NULL; +#else + inode->u.i_cdev = NULL; +#endif } spin_unlock(&cdev_lock); } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index a624c3ec..eecc2ec4 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -24,8 +24,8 @@ #include #include #include - #include +#include static struct super_operations cramfs_ops; static struct inode_operations cramfs_dir_inode_operations; @@ -35,9 +35,28 @@ static const struct address_space_operations cramfs_aops; static DEFINE_MUTEX(read_mutex); +#if defined(__LITTLE_ENDIAN) +#define le24_to_cpu(x) (x) +#define CRAMFS_GET_NAMELEN(x) ((x)->namelen) +#define CRAMFS_GET_OFFSET(x) ((x)->offset) +#endif +#if defined(__BIG_ENDIAN) +#define le24_to_cpu(x) ((le32_to_cpu(x)) >> 8) +#define CRAMFS_GET_NAMELEN(x) (((u8*)(x))[8] & 0x3f) +#define CRAMFS_GET_OFFSET(x) ((le24_to_cpu(((u32*)(x))[2] & 0xffffff) << 2) \ + | ((((u32*)(x))[2] & 0xc0000000) >> 30)) +#endif +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) +#error "neither __LITTLE_ENDIAN or __BIG_ENDIAN defined?" +#endif +#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) +#error "both __LITTLE_ENDIAN and __BIG_ENDIAN defined?" +#endif + /* These two macros may change in future, to provide better st_ino semantics. */ -#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1) +#define CRAMINO(x) ((CRAMFS_GET_OFFSET(x) && le24_to_cpu((x)->size)) ? \ + CRAMFS_GET_OFFSET(x)<<2 : 1) #define OFFSET(x) ((x)->i_ino) @@ -59,7 +78,7 @@ static int cramfs_iget5_test(struct inode *inode, void *opaque) return 0; /* does not match */ if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) && - (inode->i_rdev != old_decode_dev(cramfs_inode->size))) + (inode->i_rdev != old_decode_dev(le24_to_cpu(cramfs_inode->size)))) return 0; /* does not match */ return 1; /* matches */ @@ -69,10 +88,11 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque) { static struct timespec zerotime; struct cramfs_inode *cramfs_inode = opaque; - inode->i_mode = cramfs_inode->mode; - inode->i_uid = cramfs_inode->uid; - inode->i_size = cramfs_inode->size; - inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; + + inode->i_mode = le16_to_cpu(cramfs_inode->mode); + inode->i_uid = le16_to_cpu(cramfs_inode->uid); + inode->i_size = le24_to_cpu(cramfs_inode->size); + inode->i_blocks = (inode->i_size - 1) / 512 + 1; inode->i_gid = cramfs_inode->gid; /* Struct copy intentional */ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; @@ -94,7 +114,7 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque) inode->i_size = 0; inode->i_blocks = 0; init_special_inode(inode, inode->i_mode, - old_decode_dev(cramfs_inode->size)); + old_decode_dev(le24_to_cpu(cramfs_inode->size))); } return 0; } @@ -105,6 +125,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode), cramfs_iget5_test, cramfs_iget5_set, cramfs_inode); + if (inode && (inode->i_state & I_NEW)) { unlock_new_inode(inode); } @@ -256,12 +277,12 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) mutex_unlock(&read_mutex); /* Do sanity checks on the superblock */ - if (super.magic != CRAMFS_MAGIC) { + if (le32_to_cpu(super.magic) != CRAMFS_MAGIC) { /* check at 512 byte offset */ mutex_lock(&read_mutex); memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super)); mutex_unlock(&read_mutex); - if (super.magic != CRAMFS_MAGIC) { + if (le32_to_cpu(super.magic) != CRAMFS_MAGIC) { if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); goto out; @@ -269,31 +290,31 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) } /* get feature flags first */ - if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { + if (le32_to_cpu(super.flags) & ~CRAMFS_SUPPORTED_FLAGS) { printk(KERN_ERR "cramfs: unsupported filesystem features\n"); goto out; } /* Check that the root inode is in a sane state */ - if (!S_ISDIR(super.root.mode)) { + if (!S_ISDIR(le16_to_cpu(super.root.mode))) { printk(KERN_ERR "cramfs: root is not a directory\n"); goto out; } - root_offset = super.root.offset << 2; - if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { - sbi->size=super.size; - sbi->blocks=super.fsid.blocks; - sbi->files=super.fsid.files; + root_offset = CRAMFS_GET_OFFSET(&super.root) << 2; + if (le32_to_cpu(super.flags) & CRAMFS_FLAG_FSID_VERSION_2) { + sbi->size=le32_to_cpu(super.size); + sbi->blocks=le32_to_cpu(super.fsid.blocks); + sbi->files=le32_to_cpu(super.fsid.files); } else { sbi->size=1<<28; sbi->blocks=0; sbi->files=0; } - sbi->magic=super.magic; - sbi->flags=super.flags; + sbi->magic=le32_to_cpu(super.magic); + sbi->flags=le32_to_cpu(super.flags); if (root_offset == 0) printk(KERN_INFO "cramfs: empty filesystem"); - else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && + else if (!(le32_to_cpu(super.flags) & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && ((root_offset != sizeof(struct cramfs_super)) && (root_offset != 512 + sizeof(struct cramfs_super)))) { @@ -324,10 +345,10 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_type = CRAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; - buf->f_blocks = CRAMFS_SB(sb)->blocks; + buf->f_blocks = le32_to_cpu(CRAMFS_SB(sb)->blocks); buf->f_bfree = 0; buf->f_bavail = 0; - buf->f_files = CRAMFS_SB(sb)->files; + buf->f_files = le32_to_cpu(CRAMFS_SB(sb)->files); buf->f_ffree = 0; buf->f_namelen = CRAMFS_MAXPATHLEN; return 0; @@ -374,10 +395,10 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) * and the name padded out to 4-byte boundaries * with zeroes. */ - namelen = de->namelen << 2; + namelen = CRAMFS_GET_NAMELEN(de) << 2; memcpy(buf, name, namelen); ino = CRAMINO(de); - mode = de->mode; + mode = le16_to_cpu(de->mode); mutex_unlock(&read_mutex); nextoffset = offset + sizeof(*de) + namelen; for (;;) { @@ -410,7 +431,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s int sorted; mutex_lock(&read_mutex); - sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS; + sorted = le32_to_cpu(CRAMFS_SB(dir->i_sb)->flags) & CRAMFS_FLAG_SORTED_DIRS; while (offset < dir->i_size) { struct cramfs_inode *de; char *name; @@ -423,7 +444,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s if (sorted && (dentry->d_name.name[0] < name[0])) break; - namelen = de->namelen << 2; + namelen = CRAMFS_GET_NAMELEN(de) << 2; offset += sizeof(*de) + namelen; /* Quick check that the name is roughly the right length */ @@ -475,8 +496,8 @@ static int cramfs_readpage(struct file *file, struct page * page) start_offset = OFFSET(inode) + maxblock*4; mutex_lock(&read_mutex); if (page->index) - start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4); - compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset); + start_offset = le32_to_cpu(*(u32 *) cramfs_read(sb, blkptr_offset-4, 4)); + compr_len = (le32_to_cpu(*(u32 *) cramfs_read(sb, blkptr_offset, 4)) - start_offset); mutex_unlock(&read_mutex); pgdata = kmap(page); if (compr_len == 0) diff --git a/fs/exec.c b/fs/exec.c index d993ea1a..18375f8b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1453,6 +1453,14 @@ fail: return core_waiters; } +/* for systems with sizeof(void*) == 4: */ +#define MAPS_LINE_FORMAT4 KERN_ERR "%08lx-%08lx %s %08lx %02x:%02x %lu %s\n" + +/* for systems with sizeof(void*) == 8: */ +#define MAPS_LINE_FORMAT8 KERN_ERR "%016lx-%016lx %s %016lx %02x:%02x %lu %s\n" + +#define MAPS_LINE_FORMAT (sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8) + int do_coredump(long signr, int exit_code, struct pt_regs * regs) { char corename[CORENAME_MAX_SIZE + 1]; @@ -1465,6 +1473,104 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) int flag = 0; int ispipe = 0; +#ifdef CONFIG_COREDUMP_PRINTK + int32_t *stack=NULL; + int lines=0; + char output_buf[80]; + char *output = output_buf; + int32_t value = 0; + + printk(KERN_ERR "%s[%d] killed because of sig - %ld", current->comm, + current->pid, signr); + /* TODO + * print out mmaps. + */ + + /* + * We print out the stack. We start by pointing the stack before the + * call to do_coredump. Note that we are assuming the kernel stack is + * the same as the user stack when we are calling do_coredump. + */ + printk("\n"); + printk(KERN_ERR"STACK DUMP:\n"); + for (lines=0,stack=(int32_t *)user_stack(regs);(lines < 10) && + (stack <= (int32_t *)current->mm->start_stack);lines++) { + /* print out the address */ + output+=snprintf(output, 79-(output-output_buf), "0x%08x: ", + (unsigned)stack); + /* now print out the stack contents */ + for (;(stack <= (int32_t*)current->mm->start_stack) && + (79-(output-output_buf) > sizeof("FFFF0000 "));stack++) { + copy_from_user(&value, stack, sizeof(int32_t)); + output += snprintf(output, 79-(output-output_buf), + "%08x ", value); + } + output--; + *output++ = '\n'; + *output = '\0'; + printk(KERN_ERR "%s", output_buf); + output = output_buf; + } + show_regs(regs); +#ifdef CONFIG_MMU + { + struct mm_struct *mm=NULL; + struct vm_area_struct *map; + char buf[PAGE_SIZE]={0}; + int flags=0; + char *line; + dev_t dev = 0; + unsigned long ino = 0; + + mm = current->mm; + if (mm) + atomic_inc(&mm->mm_users); + if (!mm) + goto finished; + + down_read(&mm->mmap_sem); + map = mm->mmap; + + while (map) { + char str[5]; + + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_sb->s_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, + map->vm_file->f_vfsmnt, + buf, sizeof(buf)); + } else { + line=NULL; + } + + flags = map->vm_flags; + + str[0] = flags & VM_READ ? 'r' : '-'; + str[1] = flags & VM_WRITE ? 'w' : '-'; + str[2] = flags & VM_EXEC ? 'x' : '-'; + str[3] = flags & VM_MAYSHARE ? 's' : 'p'; + str[4] = 0; + + printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, + str, + map->vm_pgoff << PAGE_SHIFT, + MAJOR(dev), MINOR(dev), ino, line?line:""); + map = map->vm_next; + } + up_read(&mm->mmap_sem); + mmput(mm); + } +#else + /* + * How do we find base address of shared libs?? + */ +#endif + +finished: +#endif + + binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 3e7a84a1..9f361b83 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -64,10 +64,18 @@ ext2_last_byte(struct inode *inode, unsigned long page_nr) static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *dir = page->mapping->host; +#else + struct inode *dir = page->u.xx.mapping->host; +#endif int err = 0; dir->i_version++; +#if 0 // mask by Victor Yu. 02-12-2007 page->mapping->a_ops->commit_write(NULL, page, from, to); +#else + page->u.xx.mapping->a_ops->commit_write(NULL, page, from, to); +#endif if (IS_DIRSYNC(dir)) err = write_one_page(page, 1); else @@ -77,7 +85,11 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) static void ext2_check_page(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *dir = page->mapping->host; +#else + struct inode *dir = page->u.xx.mapping->host; +#endif struct super_block *sb = dir->i_sb; unsigned chunk_size = ext2_chunk_size(dir); char *kaddr = page_address(page); @@ -413,7 +425,11 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, int err; lock_page(page); +#if 0 // mask by Victor Yu. 02-12-2007 err = page->mapping->a_ops->prepare_write(NULL, page, from, to); +#else + err = page->u.xx.mapping->a_ops->prepare_write(NULL, page, from, to); +#endif BUG_ON(err); de->inode = cpu_to_le32(inode->i_ino); ext2_set_de_type (de, inode); @@ -495,7 +511,11 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) got_it: from = (char*)de - (char*)page_address(page); to = from + rec_len; +#if 0 // mask by Victor yu. 02-12-2007 err = page->mapping->a_ops->prepare_write(NULL, page, from, to); +#else + err = page->u.xx.mapping->a_ops->prepare_write(NULL, page, from, to); +#endif if (err) goto out_unlock; if (de->inode) { @@ -528,7 +548,11 @@ out_unlock: */ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif struct inode *inode = mapping->host; char *kaddr = page_address(page); unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index dd4e14c2..09a4b2e6 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -667,6 +667,7 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping,block,ext2_get_block); } +#ifdef CONFIG_DIRECTIO static ssize_t ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) @@ -677,6 +678,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext2_get_block, NULL); } +#endif static int ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) @@ -692,7 +694,9 @@ const struct address_space_operations ext2_aops = { .prepare_write = ext2_prepare_write, .commit_write = generic_commit_write, .bmap = ext2_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = ext2_direct_IO, +#endif .writepages = ext2_writepages, .migratepage = buffer_migrate_page, }; @@ -710,7 +714,9 @@ const struct address_space_operations ext2_nobh_aops = { .prepare_write = ext2_nobh_prepare_write, .commit_write = nobh_commit_write, .bmap = ext2_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = ext2_direct_IO, +#endif .writepages = ext2_writepages, .migratepage = buffer_migrate_page, }; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 03ba5bca..afde805c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1151,7 +1151,11 @@ static int do_journal_get_write_access(handle_t *handle, static int ext3_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { +#if 0 // mask by Victor Yu... 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; @@ -1211,7 +1215,11 @@ static int ext3_ordered_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { handle_t *handle = ext3_journal_current_handle(); +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int ret = 0, ret2; ret = walk_page_buffers(handle, page_buffers(page), @@ -1240,7 +1248,11 @@ static int ext3_writeback_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { handle_t *handle = ext3_journal_current_handle(); +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int ret = 0, ret2; loff_t new_i_size; @@ -1263,7 +1275,11 @@ static int ext3_journalled_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { handle_t *handle = ext3_journal_current_handle(); +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int ret = 0, ret2; int partial = 0; loff_t pos; @@ -1418,7 +1434,11 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) static int ext3_ordered_writepage(struct page *page, struct writeback_control *wbc) { +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif struct buffer_head *page_bufs; handle_t *handle = NULL; int ret = 0; @@ -1484,7 +1504,11 @@ out_fail: static int ext3_writeback_writepage(struct page *page, struct writeback_control *wbc) { +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif handle_t *handle = NULL; int ret = 0; int err; @@ -1517,7 +1541,11 @@ out_fail: static int ext3_journalled_writepage(struct page *page, struct writeback_control *wbc) { +#if 0 // mask by Victor Yu. 07-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif handle_t *handle = NULL; int ret = 0; int err; @@ -1587,7 +1615,11 @@ ext3_readpages(struct file *file, struct address_space *mapping, static void ext3_invalidatepage(struct page *page, unsigned long offset) { +#if 0 // mask by Victor Yu. 07-12-2007 journal_t *journal = EXT3_JOURNAL(page->mapping->host); +#else + journal_t *journal = EXT3_JOURNAL(page->u.xx.mapping->host); +#endif /* * If it's a full truncate we just forget about the pending dirtying @@ -1600,7 +1632,11 @@ static void ext3_invalidatepage(struct page *page, unsigned long offset) static int ext3_releasepage(struct page *page, gfp_t wait) { +#if 0 // mask by Victor Yu. 07-12-2007 journal_t *journal = EXT3_JOURNAL(page->mapping->host); +#else + journal_t *journal = EXT3_JOURNAL(page->u.xx.mapping->host); +#endif WARN_ON(PageChecked(page)); if (!page_has_buffers(page)) @@ -1608,6 +1644,7 @@ static int ext3_releasepage(struct page *page, gfp_t wait) return journal_try_to_free_buffers(journal, page, wait); } +#ifdef CONFIG_DIRECTIO /* * If the O_DIRECT write will extend the file then add this inode to the * orphan list. So recovery will truncate it back to the original size @@ -1682,6 +1719,7 @@ out_stop: out: return ret; } +#endif /* * Pages can be marked dirty completely asynchronously from ext3's journalling @@ -1712,7 +1750,9 @@ static const struct address_space_operations ext3_ordered_aops = { .bmap = ext3_bmap, .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, +#ifdef CONFIG_DIRECTIO .direct_IO = ext3_direct_IO, +#endif .migratepage = buffer_migrate_page, }; @@ -1726,7 +1766,9 @@ static const struct address_space_operations ext3_writeback_aops = { .bmap = ext3_bmap, .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, +#ifdef CONFIG_DIRECTIO .direct_IO = ext3_direct_IO, +#endif .migratepage = buffer_migrate_page, }; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 78945b53..ebd105f9 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -142,14 +142,23 @@ static int fat_readpages(struct file *file, struct address_space *mapping, static int fat_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { +#if 1 // add by Victor Yu. 03-07-2007 + return cont_prepare_write(page, from, to, fat_get_block, + &MSDOS_I(page->u.xx.mapping->host)->mmu_private); +#else return cont_prepare_write(page, from, to, fat_get_block, &MSDOS_I(page->mapping->host)->mmu_private); +#endif } static int fat_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { +#if 1 // add by Victor Yu. 03-07-2007 + struct inode *inode = page->u.xx.mapping->host; +#else struct inode *inode = page->mapping->host; +#endif int err = generic_commit_write(file, page, from, to); if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; @@ -159,6 +168,7 @@ static int fat_commit_write(struct file *file, struct page *page, return err; } +#ifdef CONFIG_DIRECTIO static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) @@ -186,6 +196,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, fat_get_block, NULL); } +#endif static sector_t _fat_bmap(struct address_space *mapping, sector_t block) { @@ -200,7 +211,9 @@ static const struct address_space_operations fat_aops = { .sync_page = block_sync_page, .prepare_write = fat_prepare_write, .commit_write = fat_commit_write, +#ifdef CONFIG_DIRECTIO .direct_IO = fat_direct_IO, +#endif .bmap = _fat_bmap }; diff --git a/fs/fifo.c b/fs/fifo.c index 49035b17..e64bb9ff 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -20,7 +20,11 @@ static void wait_for_partner(struct inode* inode, unsigned int *cnt) int cur = *cnt; while (cur == *cnt) { +#if 0 // mask by Victor Yu. 02-12-2007 pipe_wait(inode->i_pipe); +#else + pipe_wait(inode->u.i_pipe); +#endif if (signal_pending(current)) break; } @@ -28,7 +32,11 @@ static void wait_for_partner(struct inode* inode, unsigned int *cnt) static void wake_up_partner(struct inode* inode) { +#if 0 // mask by Victor Yu. 02-12-2007 wake_up_interruptible(&inode->i_pipe->wait); +#else + wake_up_interruptible(&inode->u.i_pipe->wait); +#endif } static int fifo_open(struct inode *inode, struct file *filp) @@ -37,13 +45,21 @@ static int fifo_open(struct inode *inode, struct file *filp) int ret; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 pipe = inode->i_pipe; +#else + pipe = inode->u.i_pipe; +#endif if (!pipe) { ret = -ENOMEM; pipe = alloc_pipe_info(inode); if (!pipe) goto err_nocleanup; +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe = pipe; +#else + inode->u.i_pipe = pipe; +#endif } filp->f_version = 0; diff --git a/fs/file_table.c b/fs/file_table.c index 24f25a05..bcfc9e6f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -169,8 +169,13 @@ void fastcall __fput(struct file *file) if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); +#else + if (unlikely(S_ISCHR(inode->i_mode) && inode->u.i_cdev != NULL)) + cdev_put(inode->u.i_cdev); +#endif fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 02f5573e..1d9880cb 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -98,6 +98,7 @@ static int hfs_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } +#ifdef CONFIG_DIRECTIO static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { @@ -107,6 +108,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, hfs_get_block, NULL); } +#endif static int hfs_writepages(struct address_space *mapping, struct writeback_control *wbc) @@ -131,7 +133,9 @@ const struct address_space_operations hfs_aops = { .prepare_write = hfs_prepare_write, .commit_write = generic_commit_write, .bmap = hfs_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = hfs_direct_IO, +#endif .writepages = hfs_writepages, }; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 9e367524..b25671d5 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -93,6 +93,7 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) return res ? try_to_free_buffers(page) : 0; } +#ifdef CONFIG_DIRECTIO static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { @@ -102,6 +103,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, hfsplus_get_block, NULL); } +#endif static int hfsplus_writepages(struct address_space *mapping, struct writeback_control *wbc) @@ -126,7 +128,9 @@ const struct address_space_operations hfsplus_aops = { .prepare_write = hfsplus_prepare_write, .commit_write = generic_commit_write, .bmap = hfsplus_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = hfsplus_direct_IO, +#endif .writepages = hfsplus_writepages, }; diff --git a/fs/inode.c b/fs/inode.c index 26cdb115..71fc0011 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -129,9 +129,15 @@ static struct inode *alloc_inode(struct super_block *sb) #ifdef CONFIG_QUOTA memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); #endif +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe = NULL; inode->i_bdev = NULL; inode->i_cdev = NULL; +#else + inode->u.i_pipe = NULL; + inode->u.i_bdev = NULL; + inode->u.i_cdev = NULL; +#endif inode->i_rdev = 0; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { @@ -253,9 +259,17 @@ void clear_inode(struct inode *inode) DQUOT_DROP(inode); if (inode->i_sb && inode->i_sb->s_op->clear_inode) inode->i_sb->s_op->clear_inode(inode); +#if 0 // mask by Victor Yu. 02-12-2007 if (S_ISBLK(inode->i_mode) && inode->i_bdev) +#else + if (S_ISBLK(inode->i_mode) && inode->u.i_bdev) +#endif bd_forget(inode); +#if 0 // mask by Victor Yu. 02-12-2007 if (S_ISCHR(inode->i_mode) && inode->i_cdev) +#else + if (S_ISCHR(inode->i_mode) && inode->u.i_cdev) +#endif cd_forget(inode); inode->i_state = I_CLEAR; } diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 10be5129..8bf366d6 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -60,7 +60,11 @@ static void release_buffer_page(struct buffer_head *bh) page = bh->b_page; if (!page) goto nope; +#if 0 // mask by Victor Yu.. 07-12-2007 if (page->mapping) +#else + if (page->u.xx.mapping) +#endif goto nope; /* OK, it's a truncated page */ diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index b85c686b..1e39a648 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1818,9 +1818,15 @@ repeat: if (buffer_jbd(bh)) { jh = bh2jh(bh); } else { +#if 0 // mask by Victor Yu. 07-12-20007 J_ASSERT_BH(bh, (atomic_read(&bh->b_count) > 0) || (bh->b_page && bh->b_page->mapping)); +#else + J_ASSERT_BH(bh, + (atomic_read(&bh->b_count) > 0) || + (bh->b_page && bh->b_page->u.xx.mapping)); +#endif if (!new_jh) { jbd_unlock_bh_journal_head(bh); diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index ff2a872e..889dddac 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -18,6 +18,55 @@ #include #include "nodelist.h" +#if 1 // Add by Jared 02-15-2007. Start the gargage collection. +#include +#include +static struct proc_dir_entry *proc_startstop_gc, *proc_jffs2, *proc_dirty, *proc_sector_size; +int jffs2_bstartstop_gc=0; // flag, 1:start the garbage collection, 0:stop the gargabe collection + +static int proc_write_startstop_gc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char tmpbuf[4]; + int len; + struct jffs2_sb_info *c=(struct jffs2_sb_info *)data; + + if ( count > 4 ) + len = 4; + else + len =count; + + if(copy_from_user( tmpbuf, buffer, len)) { + return -EFAULT; + } + tmpbuf[len]='\0'; + + sscanf(tmpbuf, "%d", &jffs2_bstartstop_gc); + + if ( jffs2_bstartstop_gc ) // wake up the sleeping garbage collection thread + wake_up_process(c->gc_task); + + return len; +} + +static int proc_read_startstop_gc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + return sprintf(page, "%d\n", jffs2_bstartstop_gc); +} + +static int proc_read_jffs2_dirty(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct jffs2_sb_info *c=(struct jffs2_sb_info *)data; + + return sprintf(page, "%d\n", c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size); +} + +static int proc_read_sector_size(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct jffs2_sb_info *c=(struct jffs2_sb_info *)data; + + return sprintf(page, "%d\n", c->nospc_dirty_size); +} +#endif // End: add by Jared static int jffs2_garbage_collect_thread(void *); @@ -80,6 +129,36 @@ static int jffs2_garbage_collect_thread(void *_c) c->gc_task = current; complete(&c->gc_thread_start); +#if 1 // Add by Jared 02-15-2007. Start the gargage collection. + proc_jffs2=proc_mkdir("jffs2", NULL); + if( proc_jffs2 ==NULL ) { + printk("<1>Create /proc/jffs2 fail\n"); + return -ENOMEM; + } + + proc_startstop_gc=create_proc_entry("startstop_gc", 0644, proc_jffs2); + if( proc_startstop_gc==NULL ) { + printk("<1>Create /proc/jffs2/startstop_gc fail\n"); + return -ENOMEM; + } + + proc_startstop_gc->write_proc=proc_write_startstop_gc; + proc_startstop_gc->read_proc=proc_read_startstop_gc; + proc_startstop_gc->data=(void*)_c; + + proc_dirty=create_proc_read_entry("dirty", 0444, proc_jffs2, proc_read_jffs2_dirty, (void*)_c); + if( proc_dirty==NULL ) { + printk("<1>Create /proc/jffs2/dirty fail\n"); + return -ENOMEM; + } + + proc_sector_size=create_proc_read_entry("sector_size", 0444, proc_jffs2, proc_read_sector_size, (void*)_c); + if( proc_sector_size==NULL ) { + printk("<1>Create /proc/jffs2/sector_size fail\n"); + return -ENOMEM; + } +#endif // End: add by Jared + set_user_nice(current, 10); for (;;) { diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 242875f7..084c1814 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -112,11 +112,19 @@ int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) static int jffs2_readpage (struct file *filp, struct page *pg) { +#if 0 // mask by Victor Yu. 02-12-2007 struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); +#else + struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->u.xx.mapping->host); +#endif int ret; down(&f->sem); +#if 0 // mask by Victor Yu. 02-12-2007 ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); +#else + ret = jffs2_do_readpage_unlock(pg->u.xx.mapping->host, pg); +#endif up(&f->sem); return ret; } @@ -124,7 +132,11 @@ static int jffs2_readpage (struct file *filp, struct page *pg) static int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = pg->mapping->host; +#else + struct inode *inode = pg->u.xx.mapping->host; +#endif struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; int ret = 0; @@ -211,7 +223,11 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, /* Actually commit the write from the page cache page we're looking at. * For now, we write the full page out each time. It sucks, but it's simple */ +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = pg->mapping->host; +#else + struct inode *inode = pg->u.xx.mapping->host; +#endif struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode *ri; diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index d8837699..3ff38f51 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -710,6 +710,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref up(&c->erase_free_sem); } +#if 1 // add by Victor Yu. 10-25-2007 +extern int jffs2_bstartstop_gc; +#endif int jffs2_thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; @@ -731,9 +734,21 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) */ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; +#if 0 // mask by Victor Yu. 10-25-2007 if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && (dirty > c->nospc_dirty_size)) ret = 1; +#else // add by Victor Yu. 10-25-2007 + if ( jffs2_bstartstop_gc ) { + if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger || + (dirty > c->nospc_dirty_size)) + ret = 1; + } else { + if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && + (dirty > c->nospc_dirty_size)) + ret = 1; + } +#endif D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index bc4b8106..6bd73fc7 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -321,6 +321,7 @@ static struct file_system_type jffs2_fs_type = { .name = "jffs2", .get_sb = jffs2_get_sb, .kill_sb = jffs2_kill_sb, + .fs_flags = FS_REQUIRES_DEV, }; static int __init init_jffs2_fs(void) diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 06a5c69d..afe1c1e2 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -53,11 +53,19 @@ struct jffs2_xattr_ref union { struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */ uint32_t ino; /* only used in scanning/building */ +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } uino; +#endif union { struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */ uint32_t xid; /* only used in sccanning/building */ +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } uxid; +#endif struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ }; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index f5719117..df3dc9ee 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -287,6 +287,7 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, jfs_get_block); } +#ifdef CONFIG_DIRECTIO static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { @@ -296,6 +297,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, jfs_get_block, NULL); } +#endif const struct address_space_operations jfs_aops = { .readpage = jfs_readpage, @@ -306,7 +308,9 @@ const struct address_space_operations jfs_aops = { .prepare_write = jfs_prepare_write, .commit_write = nobh_commit_write, .bmap = jfs_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = jfs_direct_IO, +#endif }; /* diff --git a/fs/libfs.c b/fs/libfs.c index bd08e0e6..8a39a497 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -343,7 +343,11 @@ int simple_prepare_write(struct file *file, struct page *page, int simple_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; /* diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index eb243edf..e277c689 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -127,8 +127,10 @@ nsm_create(void) { struct sockaddr_in sin = { .sin_family = AF_INET, +#if 0 // mask by Victor Yu. 02-12-2007 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), .sin_port = 0, +#endif }; struct rpc_create_args args = { .protocol = IPPROTO_UDP, @@ -141,6 +143,10 @@ nsm_create(void) .flags = (RPC_CLNT_CREATE_ONESHOT), }; +#if 1 // add by Victor Yu. 02-12-2007 + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = 0; +#endif return rpc_create(&args); } diff --git a/fs/mpage.c b/fs/mpage.c index 692a3e57..097d3629 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -81,8 +81,13 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) if (!uptodate){ SetPageError(page); +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping) set_bit(AS_EIO, &page->mapping->flags); +#else + if (page->u.xx.mapping) + set_bit(AS_EIO, &page->u.xx.mapping->flags); +#endif } end_page_writeback(page); } while (bvec >= bio->bi_io_vec); @@ -133,7 +138,11 @@ mpage_alloc(struct block_device *bdev, static void map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif struct buffer_head *page_bh, *head; int block = 0; @@ -177,7 +186,11 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, sector_t *last_block_in_bio, struct buffer_head *map_bh, unsigned long *first_logical_block, get_block_t get_block) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif const unsigned blkbits = inode->i_blkbits; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; const unsigned blocksize = 1 << blkbits; @@ -461,8 +474,13 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc, writepage_t writepage_fn) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; struct inode *inode = page->mapping->host; +#else + struct address_space *mapping = page->u.xx.mapping; + struct inode *inode = page->u.xx.mapping->host; +#endif const unsigned blkbits = inode->i_blkbits; unsigned long end_index; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; @@ -754,7 +772,11 @@ retry: lock_page(page); +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(page->mapping != mapping)) { +#else + if (unlikely(page->u.xx.mapping != mapping)) { +#endif unlock_page(page); continue; } @@ -785,9 +807,15 @@ retry: &mapping->flags); } } else { +#if 0 // mask by Victor Yu. 02-12-2007 bio = __mpage_writepage(bio, page, get_block, &last_block_in_bio, &ret, wbc, page->mapping->a_ops->writepage); +#else + bio = __mpage_writepage(bio, page, get_block, + &last_block_in_bio, &ret, wbc, + page->u.xx.mapping->a_ops->writepage); +#endif } if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) unlock_page(page); diff --git a/fs/namei.c b/fs/namei.c index 28d49b30..87392454 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -120,12 +120,14 @@ static int do_getname(const char __user *filename, char *page) int retval; unsigned long len = PATH_MAX; +#ifdef CONFIG_MMU if (!segment_eq(get_fs(), KERNEL_DS)) { if ((unsigned long) filename >= TASK_SIZE) return -EFAULT; if (TASK_SIZE - (unsigned long) filename < PATH_MAX) len = TASK_SIZE - (unsigned long) filename; } +#endif retval = strncpy_from_user(page, filename, len); if (retval > 0) { diff --git a/fs/nfs/file.c b/fs/nfs/file.c index cc93865c..8db13352 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -307,7 +307,11 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse static void nfs_invalidate_page(struct page *page, unsigned long offset) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif /* Cancel any unstarted writes on this page */ if (offset == 0) @@ -317,7 +321,11 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) static int nfs_release_page(struct page *page, gfp_t gfp) { if (gfp & __GFP_FS) +#if 0 // mask by Victor Yu. 02-12-2007 return !nfs_wb_page(page->mapping->host, page); +#else + return !nfs_wb_page(page->u.xx.mapping->host, page); +#endif else /* * Avoid deadlock on nfs_wait_on_request(). diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 829af323..100a74f0 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -86,7 +86,11 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, page_cache_get(page); BUG_ON(PagePrivate(page)); BUG_ON(!PageLocked(page)); +#if 0 // mask by Victor yu. 02-12-2007 BUG_ON(page->mapping->host != inode); +#else + BUG_ON(page->u.xx.mapping->host != inode); +#endif req->wb_offset = offset; req->wb_pgbase = offset; req->wb_bytes = count; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c2e49c39..557b1f8d 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -602,7 +602,11 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) int nfs_readpage(struct file *file, struct page *page) { struct nfs_open_context *ctx; +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif int error; dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", @@ -658,7 +662,11 @@ static int readpage_async_filler(void *data, struct page *page) { struct nfs_readdesc *desc = (struct nfs_readdesc *)data; +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif struct nfs_page *new; unsigned int len; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 883dd4a1..37516db1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -146,7 +146,11 @@ void nfs_writedata_release(void *wdata) /* Adjust the file length if we're writing beyond the end */ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) { +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif loff_t end, i_size = i_size_read(inode); unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; @@ -175,7 +179,11 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int return; } +#if 0 // mask by Victor Yu. 02-12-2007 end_offs = i_size_read(page->mapping->host) - 1; +#else + end_offs = i_size_read(page->u.xx.mapping->host) - 1; +#endif if (end_offs < 0) return; /* Is this the last page? */ @@ -294,7 +302,11 @@ static int wb_priority(struct writeback_control *wbc) int nfs_writepage(struct page *page, struct writeback_control *wbc) { struct nfs_open_context *ctx; +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif unsigned long end_index; unsigned offset = PAGE_CACHE_SIZE; loff_t i_size = i_size_read(inode); @@ -708,7 +720,11 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, end = offset + bytes; +#if 0 // mask by Victor Yu. 02-12-2007 if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR)) +#else + if (nfs_wait_on_write_congestion(page->u.xx.mapping, server->flags & NFS_MOUNT_INTR)) +#endif return ERR_PTR(-ERESTARTSYS); for (;;) { /* Loop over all inode entries and see if we find @@ -786,7 +802,11 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, int nfs_flush_incompatible(struct file *file, struct page *page) { struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif struct nfs_page *req; int status = 0; /* @@ -816,7 +836,11 @@ int nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; +#if 0 // mask by Victor Yu. 02-12-2007 struct inode *inode = page->mapping->host; +#else + struct inode *inode = page->u.xx.mapping->host; +#endif struct nfs_page *req; int status = 0; diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 3d7c082a..4d1b9c0d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -523,6 +523,7 @@ bail: return status; } +#ifdef CONFIG_DIRECTIO /* * TODO: Make this into a generic get_blocks function. * @@ -643,6 +644,7 @@ out: mlog_exit(ret); return ret; } +#endif const struct address_space_operations ocfs2_aops = { .readpage = ocfs2_readpage, @@ -651,5 +653,7 @@ const struct address_space_operations ocfs2_aops = { .commit_write = ocfs2_commit_write, .bmap = ocfs2_bmap, .sync_page = block_sync_page, +#ifdef CONFIG_DIRECTIO .direct_IO = ocfs2_direct_IO +#endif }; diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 1a60926a..49e026ec 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c @@ -101,6 +101,9 @@ static int ldm_parse_hexbyte (const u8 *src) * Return: 'true' @dest contains binary GUID * 'false' @dest contents are undefined */ +#if 1 // add by Victor Yu. 03-07-2007 +typedef int bool; +#endif static bool ldm_parse_guid (const u8 *src, u8 *dest) { static const int size[] = { 4, 2, 2, 2, 6 }; diff --git a/fs/pipe.c b/fs/pipe.c index b1626f26..15a5af6c 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -237,7 +237,11 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, do_wakeup = 0; ret = 0; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 pipe = inode->i_pipe; +#else + pipe = inode->u.i_pipe; +#endif for (;;) { int bufs = pipe->nrbufs; if (bufs) { @@ -351,7 +355,11 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, do_wakeup = 0; ret = 0; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 pipe = inode->i_pipe; +#else + pipe = inode->u.i_pipe; +#endif if (!pipe->readers) { send_sig(SIGPIPE, current, 0); @@ -527,7 +535,11 @@ pipe_ioctl(struct inode *pino, struct file *filp, switch (cmd) { case FIONREAD: mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 pipe = inode->i_pipe; +#else + pipe = inode->u.i_pipe; +#endif count = 0; buf = pipe->curbuf; nrbufs = pipe->nrbufs; @@ -549,7 +561,11 @@ pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; +#if 0 // mask by Victor Yu. 02-12-2007 struct pipe_inode_info *pipe = inode->i_pipe; +#else + struct pipe_inode_info *pipe = inode->u.i_pipe; +#endif int nrbufs; poll_wait(filp, &pipe->wait, wait); @@ -582,7 +598,11 @@ pipe_release(struct inode *inode, int decr, int decw) struct pipe_inode_info *pipe; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 pipe = inode->i_pipe; +#else + pipe = inode->u.i_pipe; +#endif pipe->readers -= decr; pipe->writers -= decw; @@ -605,7 +625,11 @@ pipe_read_fasync(int fd, struct file *filp, int on) int retval; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers); +#else + retval = fasync_helper(fd, filp, on, &inode->u.i_pipe->fasync_readers); +#endif mutex_unlock(&inode->i_mutex); if (retval < 0) @@ -622,7 +646,11 @@ pipe_write_fasync(int fd, struct file *filp, int on) int retval; mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_writers); +#else + retval = fasync_helper(fd, filp, on, &inode->u.i_pipe->fasync_writers); +#endif mutex_unlock(&inode->i_mutex); if (retval < 0) @@ -636,7 +664,11 @@ static int pipe_rdwr_fasync(int fd, struct file *filp, int on) { struct inode *inode = filp->f_dentry->d_inode; +#if 0 // mask by Victor Yu. 02-12-2007 struct pipe_inode_info *pipe = inode->i_pipe; +#else + struct pipe_inode_info *pipe = inode->u.i_pipe; +#endif int retval; mutex_lock(&inode->i_mutex); @@ -686,7 +718,11 @@ pipe_read_open(struct inode *inode, struct file *filp) /* We could have perhaps used atomic_t, but this and friends below are the only places. So it doesn't seem worthwhile. */ mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe->readers++; +#else + inode->u.i_pipe->readers++; +#endif mutex_unlock(&inode->i_mutex); return 0; @@ -696,7 +732,11 @@ static int pipe_write_open(struct inode *inode, struct file *filp) { mutex_lock(&inode->i_mutex); +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe->writers++; +#else + inode->u.i_pipe->writers++; +#endif mutex_unlock(&inode->i_mutex); return 0; @@ -707,9 +747,17 @@ pipe_rdwr_open(struct inode *inode, struct file *filp) { mutex_lock(&inode->i_mutex); if (filp->f_mode & FMODE_READ) +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe->readers++; +#else + inode->u.i_pipe->readers++; +#endif if (filp->f_mode & FMODE_WRITE) +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe->writers++; +#else + inode->u.i_pipe->writers++; +#endif mutex_unlock(&inode->i_mutex); return 0; @@ -823,8 +871,13 @@ void __free_pipe_info(struct pipe_inode_info *pipe) void free_pipe_info(struct inode *inode) { +#if 0 // mask by Victor Yu. 02-12-2007 __free_pipe_info(inode->i_pipe); inode->i_pipe = NULL; +#else + __free_pipe_info(inode->u.i_pipe); + inode->u.i_pipe = NULL; +#endif } static struct vfsmount *pipe_mnt __read_mostly; @@ -848,7 +901,11 @@ static struct inode * get_pipe_inode(void) pipe = alloc_pipe_info(inode); if (!pipe) goto fail_iput; +#if 0 // mask by Victor Yu. 02-12-2007 inode->i_pipe = pipe; +#else + inode->u.i_pipe = pipe; +#endif pipe->readers = pipe->writers = 1; inode->i_fop = &rdwr_pipe_fops; diff --git a/fs/proc/base.c b/fs/proc/base.c index 795319c5..362dea44 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -691,8 +691,8 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, if (copy_from_user(buffer, buf, count)) return -EFAULT; oom_adjust = simple_strtol(buffer, &end, 0); - if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && - oom_adjust != OOM_DISABLE) + if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE + && oom_adjust != OOM_DISABLE_NOINHERIT) return -EINVAL; if (*end == '\n') end++; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 9c69bcac..e7bab1c4 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -450,7 +450,8 @@ static int reiserfs_get_block_create_0(struct inode *inode, sector_t block, { return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE); } - + +#ifdef CONFIG_DIRECTIO /* This is special helper for reiserfs_get_block in case we are executing direct_IO request. */ static int reiserfs_get_blocks_direct_io(struct inode *inode, @@ -494,6 +495,7 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, out: return ret; } +#endif /* ** helper function for when reiserfs_get_block is called for a hole @@ -2886,6 +2888,7 @@ static int reiserfs_releasepage(struct page *page, gfp_t unused_gfp_flags) return ret; } +#ifdef CONFIG_DIRECTIO /* We thank Mingming Cao for helping us understand in great detail what to do in this section of the code. */ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, @@ -2899,6 +2902,7 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); } +#endif int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { @@ -3010,6 +3014,8 @@ const struct address_space_operations reiserfs_address_space_operations = { .prepare_write = reiserfs_prepare_write, .commit_write = reiserfs_commit_write, .bmap = reiserfs_aop_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = reiserfs_direct_IO, +#endif .set_page_dirty = reiserfs_set_page_dirty, }; diff --git a/fs/splice.c b/fs/splice.c index da74583a..66be3940 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -114,7 +114,11 @@ static int page_cache_pipe_buf_pin(struct pipe_inode_info *pipe, * Page got truncated/unhashed. This will cause a 0-byte * splice, if this is the first page. */ +#if 0 // mask by Victor Yu. 02-12-2007 if (!page->mapping) { +#else + if (!page->u.xx.mapping) { +#endif err = -ENODATA; goto error; } @@ -388,7 +392,11 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, * first page, we'll just complete what we already * added */ +#if 0 // mask by Victor Yu. 02-12-2007 if (!page->mapping) { +#else + if (!page->u.xx.mapping) { +#endif unlock_page(page); break; } @@ -635,7 +643,11 @@ find_page: /* * Page got invalidated, repeat. */ +#if 0 // mask by Victor Yu. 02-12-2007 if (!page->mapping) { +#else + if (!page->u.xx.mapping) { +#endif unlock_page(page); page_cache_release(page); goto find_page; @@ -1116,7 +1128,11 @@ EXPORT_SYMBOL(do_splice_direct); static inline struct pipe_inode_info *pipe_info(struct inode *inode) { if (S_ISFIFO(inode->i_mode)) +#if 0 // mask by Victor Yu. 02-12-2007 return inode->i_pipe; +#else + return inode->u.i_pipe; +#endif return NULL; } diff --git a/fs/squashfs/LzmaDecode.c b/fs/squashfs/LzmaDecode.c new file mode 100644 index 00000000..292b3a74 --- /dev/null +++ b/fs/squashfs/LzmaDecode.c @@ -0,0 +1,648 @@ +/* +LzmaDecode.c +LZMA Decoder +LZMA SDK 4.01 Copyright (c) 1999-2004 Igor Pavlov (2004-02-15) +*/ + +#include "LzmaDecode.h" + +#ifndef Byte +#define Byte unsigned char +#endif + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +typedef struct _CRangeDecoder +{ + Byte *Buffer; + Byte *BufferLim; + UInt32 Range; + UInt32 Code; + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback; + int Result; + #endif + int ExtraBytes; +} CRangeDecoder; + +Byte RangeDecoderReadByte(CRangeDecoder *rd) +{ + if (rd->Buffer == rd->BufferLim) + { + #ifdef _LZMA_IN_CB + UInt32 size; + rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size); + rd->BufferLim = rd->Buffer + size; + if (size == 0) + #endif + { + rd->ExtraBytes = 1; + return 0xFF; + } + } + return (*rd->Buffer++); +} + +/* #define ReadByte (*rd->Buffer++) */ +#define ReadByte (RangeDecoderReadByte(rd)) + +void RangeDecoderInit(CRangeDecoder *rd, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + Byte *stream, UInt32 bufferSize + #endif + ) +{ + int i; + #ifdef _LZMA_IN_CB + rd->InCallback = inCallback; + rd->Buffer = rd->BufferLim = 0; + #else + rd->Buffer = stream; + rd->BufferLim = stream + bufferSize; + #endif + rd->ExtraBytes = 0; + rd->Code = 0; + rd->Range = (0xFFFFFFFF); + for(i = 0; i < 5; i++) + rd->Code = (rd->Code << 8) | ReadByte; +} + +#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code; +#define RC_FLUSH_VAR rd->Range = range; rd->Code = code; +#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; } + +UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits) +{ + RC_INIT_VAR + UInt32 result = 0; + int i; + for (i = numTotalBits; i > 0; i--) + { + /* UInt32 t; */ + range >>= 1; + + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + /* + t = (code - range) >> 31; + t &= 1; + code -= range & (t - 1); + result = (result + result) | (1 - t); + */ + RC_NORMALIZE + } + RC_FLUSH_VAR + return result; +} + +int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd) +{ + UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob; + if (rd->Code < bound) + { + rd->Range = bound; + *prob += (kBitModelTotal - *prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 0; + } + else + { + rd->Range -= bound; + rd->Code -= bound; + *prob -= (*prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 1; + } +} + +#define RC_GET_BIT2(prob, mi, A0, A1) \ + UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \ + if (code < bound) \ + { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \ + else \ + { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \ + RC_NORMALIZE + +#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;) + +int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = numLevels; i > 0; i--) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT(prob, mi) + #else + mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return mi - (1 << numLevels); +} + +int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + int symbol = 0; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = 0; i < numLevels; i++) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i)) + #else + int bit = RangeDecoderBitDecode(probs + mi, rd); + mi = mi + mi + bit; + symbol |= (bit << i); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + int bit; + int matchBit = (matchByte >> 7) & 1; + matchByte <<= 1; + #ifdef _LZMA_LOC_OPT + { + CProb *prob = probs + ((1 + matchBit) << 8) + symbol; + RC_GET_BIT2(prob, symbol, bit = 0, bit = 1) + } + #else + bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd); + symbol = (symbol << 1) | bit; + #endif + if (matchBit != bit) + { + while (symbol < 0x100) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + break; + } + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState) +{ + if(RangeDecoderBitDecode(p + LenChoice, rd) == 0) + return RangeDecoderBitTreeDecode(p + LenLow + + (posState << kLenNumLowBits), kLenNumLowBits, rd); + if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0) + return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid + + (posState << kLenNumMidBits), kLenNumMidBits, rd); + return kLenNumLowSymbols + kLenNumMidSymbols + + RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd); +} + +#define kNumStates 12 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#ifdef _LZMA_OUT_READ + +typedef struct _LzmaVarState +{ + CRangeDecoder RangeDecoder; + Byte *Dictionary; + UInt32 DictionarySize; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 Reps[4]; + int lc; + int lp; + int pb; + int State; + int PreviousIsMatch; + int RemainLen; +} LzmaVarState; + +int LzmaDecoderInit( + unsigned char *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + unsigned char *dictionary, UInt32 dictionarySize, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + unsigned char *inStream, UInt32 inSize + #endif + ) +{ + LzmaVarState *vs = (LzmaVarState *)buffer; + CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); + UInt32 i; + if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState)) + return LZMA_RESULT_NOT_ENOUGH_MEM; + vs->Dictionary = dictionary; + vs->DictionarySize = dictionarySize; + vs->DictionaryPos = 0; + vs->GlobalPos = 0; + vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1; + vs->lc = lc; + vs->lp = lp; + vs->pb = pb; + vs->State = 0; + vs->PreviousIsMatch = 0; + vs->RemainLen = 0; + dictionary[dictionarySize - 1] = 0; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + RangeDecoderInit(&vs->RangeDecoder, + #ifdef _LZMA_IN_CB + inCallback + #else + inStream, inSize + #endif + ); + return LZMA_RESULT_OK; +} + +int LzmaDecode(unsigned char *buffer, + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed) +{ + LzmaVarState *vs = (LzmaVarState *)buffer; + CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); + CRangeDecoder rd = vs->RangeDecoder; + int state = vs->State; + int previousIsMatch = vs->PreviousIsMatch; + Byte previousByte; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + UInt32 nowPos = 0; + UInt32 posStateMask = (1 << (vs->pb)) - 1; + UInt32 literalPosMask = (1 << (vs->lp)) - 1; + int lc = vs->lc; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + if (len == -1) + { + *outSizeProcessed = 0; + return LZMA_RESULT_OK; + } + + while(len > 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; +#else + +int LzmaDecode( + Byte *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + unsigned char *inStream, UInt32 inSize, + #endif + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); + CProb *p = (CProb *)buffer; + CRangeDecoder rd; + UInt32 i; + int state = 0; + int previousIsMatch = 0; + Byte previousByte = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + UInt32 nowPos = 0; + UInt32 posStateMask = (1 << pb) - 1; + UInt32 literalPosMask = (1 << lp) - 1; + int len = 0; + if (bufferSize < numProbs * sizeof(CProb)) + return LZMA_RESULT_NOT_ENOUGH_MEM; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + RangeDecoderInit(&rd, + #ifdef _LZMA_IN_CB + inCallback + #else + inStream, inSize + #endif + ); +#endif + + *outSizeProcessed = 0; + while(nowPos < outSize) + { + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + #ifdef _LZMA_IN_CB + if (rd.Result != LZMA_RESULT_OK) + return rd.Result; + #endif + if (rd.ExtraBytes != 0) + return LZMA_RESULT_DATA_ERROR; + if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + CProb *probs = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + if (previousIsMatch) + { + Byte matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte); + previousIsMatch = 0; + } + else + previousByte = LzmaLiteralDecode(probs, &rd); + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + } + else + { + previousIsMatch = 1; + if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1) + { + if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0) + { + if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + if ( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + == 0) + return LZMA_RESULT_DATA_ERROR; + state = state < 7 ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + continue; + } + } + else + { + UInt32 distance; + if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0) + distance = rep1; + else + { + if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = LzmaLenDecode(p + RepLenCoder, &rd, posState); + state = state < 7 ? 8 : 11; + } + else + { + int posSlot; + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < 7 ? 7 : 10; + len = LzmaLenDecode(p + LenCoder, &rd, posState); + posSlot = RangeDecoderBitTreeDecode(p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits), kNumPosSlotBits, &rd); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits); + if (posSlot < kEndPosModelIndex) + { + rep0 += RangeDecoderReverseBitTreeDecode( + p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd); + } + else + { + rep0 += RangeDecoderDecodeDirectBits(&rd, + numDirectBits - kNumAlignBits) << kNumAlignBits; + rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd); + } + } + else + rep0 = posSlot; + rep0++; + } + if (rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = -1; + break; + } + if (rep0 > nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + { + return LZMA_RESULT_DATA_ERROR; + } + len += kMatchMinLen; + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + len--; + } + while(len > 0 && nowPos < outSize); + } + } + + #ifdef _LZMA_OUT_READ + vs->RangeDecoder = rd; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + nowPos; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->PreviousIsMatch = previousIsMatch; + vs->RemainLen = len; + #endif + + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/fs/squashfs/LzmaDecode.h b/fs/squashfs/LzmaDecode.h new file mode 100644 index 00000000..49b7ae0d --- /dev/null +++ b/fs/squashfs/LzmaDecode.h @@ -0,0 +1,85 @@ +/* +LzmaDecode.h +LZMA Decoder interface +LZMA SDK 4.01 Copyright (c) 1999-2004 Igor Pavlov (2004-02-15) +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +#ifndef UInt32 +#ifdef _LZMA_UINT32_IS_ULONG +#define UInt32 unsigned long +#else +#define UInt32 unsigned int +#endif +#endif + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb unsigned short +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 +#define LZMA_RESULT_NOT_ENOUGH_MEM 2 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +/* +bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb) +bufferSize += 100 in case of _LZMA_OUT_READ +by default CProb is unsigned short, +but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int) +*/ + +#ifdef _LZMA_OUT_READ +int LzmaDecoderInit( + unsigned char *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + unsigned char *dictionary, UInt32 dictionarySize, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + unsigned char *inStream, UInt32 inSize + #endif +); +#endif + +int LzmaDecode( + unsigned char *buffer, + #ifndef _LZMA_OUT_READ + UInt32 bufferSize, + int lc, int lp, int pb, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + unsigned char *inStream, UInt32 inSize, + #endif + #endif + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed); + +#endif diff --git a/fs/squashfs/LzmaWrapper.c b/fs/squashfs/LzmaWrapper.c new file mode 100644 index 00000000..a8ec90bb --- /dev/null +++ b/fs/squashfs/LzmaWrapper.c @@ -0,0 +1,90 @@ +/* + LzmaTest.c + Test application for LZMA Decoder + LZMA SDK 4.01 Copyright (c) 1999-2004 Igor Pavlov (2004-02-15) + */ + +#include +#include +#include "LzmaDecode.h" +#include "LzmaWrapper.h" + +static int internal_size; +static unsigned char *internal_data=0; +//static int dictionary_size; + +int lzma_workspace_size(void) +{ +// int pb=2; + int lp=0; + int lc=3; + + return (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb); +} + +int lzma_init(unsigned char *data, int size) +{ + internal_data=data; + internal_size=size; + return 0; +} + +int lzma_inflate( + unsigned char *source, + int s_len, + unsigned char *dest, + int *d_len) +{ + /* Get the properties */ + unsigned int check_internal_size; + unsigned char properties[5]; + unsigned char prop0; + int lc, lp, pb; + int res, i; + unsigned int dictionary_size = 0; + unsigned int encoded_size; + + if(s_len<5){ + /* Can't even get properities, just exit */ + return LZMA_ERROR; + } + + /* Get the size of the uncompressed buffer */ + encoded_size = + source[0] | (source[1] << 8) | (source[2] << 16) | (source[3] << 24); + source+=4; + + /* We use this to check that the size of internal data structures + are big enough. If it isn't, then we flag it. */ + memcpy(properties, source, sizeof(properties)); + prop0 = properties[0]; + if (prop0 >= (9*5*5)) + return LZMA_ERROR; + for (pb = 0; prop0 >= (9 * 5); + pb++, prop0 -= (9 * 5)); + for (lp = 0; prop0 >= 9; + lp++, prop0 -= 9); + lc = prop0; + + source += 5; + + check_internal_size = + (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb); + + for (i = 0; i < 4; i++) + dictionary_size += (UInt32)(properties[1 + i]) << (i * 8); + + if(check_internal_size > internal_size){ + printk("internal_size = %d, header size = %d\n", internal_size, check_internal_size); + printk("lc = %d, lp=%d, pb=%d\n", lc, lp, pb); + printk("byte=%x, dictionary size = %8.8x\n", prop0, dictionary_size); + return LZMA_TOO_BIG; + } + + res = LzmaDecode(internal_data, internal_size, + lc, lp, pb, + (unsigned char *)source, s_len, + (unsigned char *)dest, encoded_size, d_len); + + return res; +} diff --git a/fs/squashfs/LzmaWrapper.h b/fs/squashfs/LzmaWrapper.h new file mode 100644 index 00000000..aac7e04b --- /dev/null +++ b/fs/squashfs/LzmaWrapper.h @@ -0,0 +1,13 @@ +#ifndef __LZMA_WRAPPER_H__ +#define __LZMA_WRAPPER_H__ + + +#define LZMA_OK 0 +#define LZMA_ERROR -1 +#define LZMA_TOO_BIG -2 + +int lzma_inflate(unsigned char *source, int s_len, unsigned char *dest, int *d_len); +int lzma_init(unsigned char *data, int size); +int lzma_workspace_size(void); + +#endif /*__LZMA_WRAPPER_H__*/ diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile new file mode 100644 index 00000000..82177e26 --- /dev/null +++ b/fs/squashfs/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux squashfs routines. +# + +obj-$(CONFIG_SQUASHFS) += squashfs.o + +squashfs-objs := inode.o +ifdef CONFIG_SQUASHFS_LZMA +squashfs-objs += LzmaDecode.o LzmaWrapper.o +endif diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c new file mode 100644 index 00000000..f64dcd51 --- /dev/null +++ b/fs/squashfs/inode.c @@ -0,0 +1,1846 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005 Phillip Lougher + * + * 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, + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * inode.c + */ + +#define SQUASHFS_1_0_COMPATIBILITY + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SQUASHFS_LZMA +#include "LzmaWrapper.h" +#else +#include +#endif + +#include +#include + +#ifdef SQUASHFS_TRACE +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) +#else +#define TRACE(s, args...) {} +#endif + +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) + +#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args) +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) + +static void squashfs_put_super(struct super_block *); +static int squashfs_statfs(struct dentry *, struct kstatfs *); +static int squashfs_symlink_readpage(struct file *file, struct page *page); +static int squashfs_readpage(struct file *file, struct page *page); +static int squashfs_readpage4K(struct file *file, struct page *page); +static int squashfs_readdir(struct file *, void *, filldir_t); +static struct dentry *squashfs_lookup(struct inode *, struct dentry *, struct nameidata *); +static unsigned int read_data(struct super_block *s, char *buffer, + unsigned int index, unsigned int length, unsigned int *next_index); +static int squashfs_get_cached_block(struct super_block *s, char *buffer, + unsigned int block, unsigned int offset, int length, + unsigned int *next_block, unsigned int *next_offset); +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode); +static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, + char *block_list, unsigned short **block_p, unsigned int *bsize); +static void squashfs_put_super(struct super_block *s); +static int squashfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); +static struct inode *squashfs_alloc_inode(struct super_block *sb); +static void squashfs_destroy_inode(struct inode *inode); +static int init_inodecache(void); +static void destroy_inodecache(void); + +#ifdef SQUASHFS_1_0_COMPATIBILITY +static int squashfs_readpage_lessthan4K(struct file *file, struct page *page); +static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode); +static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, + char *block_list, unsigned short **block_p, unsigned int *bsize); +#endif + +DECLARE_MUTEX(read_data_mutex); + +#ifdef CONFIG_SQUASHFS_LZMA +static char *lzma_data; +#else +static z_stream stream; +#endif + +static struct file_system_type squashfs_fs_type = { + .owner = THIS_MODULE, + .name = "squashfs", + .get_sb = squashfs_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV + }; + +static unsigned char squashfs_filetype_table[] = { + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK +}; + +static struct super_operations squashfs_ops = { + .alloc_inode = squashfs_alloc_inode, + .destroy_inode = squashfs_destroy_inode, + .statfs = squashfs_statfs, + .put_super = squashfs_put_super, +}; + +static struct address_space_operations squashfs_symlink_aops = { + .readpage = squashfs_symlink_readpage +}; + +static struct address_space_operations squashfs_aops = { + .readpage = squashfs_readpage +}; + +static struct address_space_operations squashfs_aops_4K = { + .readpage = squashfs_readpage4K +}; + +#ifdef SQUASHFS_1_0_COMPATIBILITY +static struct address_space_operations squashfs_aops_lessthan4K = { + .readpage = squashfs_readpage_lessthan4K +}; +#endif + +static struct file_operations squashfs_dir_ops = { + .read = generic_read_dir, + .readdir = squashfs_readdir +}; + +static struct inode_operations squashfs_dir_inode_ops = { + .lookup = squashfs_lookup +}; + + +static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) +{ + return list_entry(inode, struct squashfs_inode_info, vfs_inode); +} + + +static struct buffer_head *get_block_length(struct super_block *s, + int *cur_index, int *offset, int *c_byte) +{ + squashfs_sb_info *msblk = s->s_fs_info; + unsigned short temp; + struct buffer_head *bh; + + if (!(bh = sb_bread(s, *cur_index))) + goto out; + + if (msblk->devblksize - *offset == 1) { + if (msblk->swap) + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + else + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + if (msblk->swap) + ((unsigned char *) &temp)[0] = *((unsigned char *) + bh->b_data); + else + ((unsigned char *) &temp)[1] = *((unsigned char *) + bh->b_data); + *c_byte = temp; + *offset = 1; + } else { + if (msblk->swap) { + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } else { + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } + *c_byte = temp; + *offset += 2; + } + + if (SQUASHFS_CHECK_DATA(msblk->sBlk.flags)) { + if (*offset == msblk->devblksize) { + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + *offset = 0; + } + if (*((unsigned char *) (bh->b_data + *offset)) != + SQUASHFS_MARKER_BYTE) { + ERROR("Metadata block marker corrupt @ %x\n", + *cur_index); + brelse(bh); + goto out; + } + (*offset)++; + } + return bh; + +out: + return NULL; +} + + +static unsigned int read_data(struct super_block *s, char *buffer, + unsigned int index, unsigned int length, unsigned int *next_index) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2]; + unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1); + unsigned int cur_index = index >> msBlk->devblksize_log2; + int bytes, avail_bytes, b = 0, k; + char *c_buffer; + unsigned int compressed; + unsigned int c_byte = length; + + if(c_byte) { + bytes = msBlk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); + c_buffer = compressed ? msBlk->read_data : buffer; + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); + + TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + + if(!(bh[0] = sb_getblk(s, cur_index))) + goto block_release; + for(b = 1; bytes < c_byte; b++) { + if(!(bh[b] = sb_getblk(s, ++cur_index))) + goto block_release; + bytes += msBlk->devblksize; + } + ll_rw_block(READ, b, bh); + } else { + if(!(bh[0] = get_block_length(s, &cur_index, &offset, &c_byte))) + goto read_failure; + + bytes = msBlk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED(c_byte); + c_buffer = compressed ? msBlk->read_data : buffer; + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); + + TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + + for(b = 1; bytes < c_byte; b++) { + if(!(bh[b] = sb_getblk(s, ++cur_index))) + goto block_release; + bytes += msBlk->devblksize; + } + ll_rw_block(READ, b - 1, bh + 1); + } + + if(compressed) + down(&read_data_mutex); + + for(bytes = 0, k = 0; k < b; k++) { + avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes; + wait_on_buffer(bh[k]); + if (!buffer_uptodate(bh[k])) + goto block_release; + memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes); + bytes += avail_bytes; + offset = 0; + brelse(bh[k]); + } + + /* + * uncompress block + */ + if(compressed) { +#ifdef CONFIG_SQUASHFS_LZMA + int out_size; + int lzma_err; + out_size=msBlk->read_size; + + if((lzma_err=lzma_inflate(c_buffer, c_byte, buffer, &out_size))){ + ERROR("lzma returned unexpected result 0x%x\n", lzma_err); + bytes = 0; + } else + bytes = out_size; +// printk("out size = %d, processed = %d\n", msBlk->read_size, out_size); +#else + int zlib_err; + + stream.next_in = c_buffer; + stream.avail_in = c_byte; + stream.next_out = buffer; + stream.avail_out = msBlk->read_size; + if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) || + ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) || + ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) { + ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err); + bytes = 0; + } else + bytes = stream.total_out; +#endif + up(&read_data_mutex); + } + + if(next_index) + *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2)); + + return bytes; + +block_release: + while(--b >= 0) brelse(bh[b]); + +read_failure: + ERROR("sb_bread failed reading block 0x%x\n", cur_index); + return 0; +} + + +static int squashfs_get_cached_block(struct super_block *s, char *buffer, + unsigned int block, unsigned int offset, int length, + unsigned int *next_block, unsigned int *next_offset) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + int n, i, bytes, return_length = length; + unsigned int next_index; + + TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset); + + for(;;) { + for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) + if(msBlk->block_cache[i].block == block) + break; + + down(&msBlk->block_cache_mutex); + if(i == SQUASHFS_CACHED_BLKS) { + /* read inode header block */ + for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS) + if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK) + break; + if(n == 0) { + wait_queue_t wait; + + init_waitqueue_entry(&wait, current); + add_wait_queue(&msBlk->waitq, &wait); + up(&msBlk->block_cache_mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&msBlk->waitq, &wait); + continue; + } + msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; + + if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) { + if(!(msBlk->block_cache[i].data = (unsigned char *) + kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) { + ERROR("Failed to allocate cache block\n"); + up(&msBlk->block_cache_mutex); + return 0; + } + } + + msBlk->block_cache[i].block = SQUASHFS_USED_BLK; + up(&msBlk->block_cache_mutex); + if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, + &next_index))) { + ERROR("Unable to read cache block [%x:%x]\n", block, offset); + return 0; + } + down(&msBlk->block_cache_mutex); + wake_up(&msBlk->waitq); + msBlk->block_cache[i].block = block; + msBlk->block_cache[i].next_index = next_index; + TRACE("Read cache block [%x:%x]\n", block, offset); + } + + if(msBlk->block_cache[i].block != block) { + up(&msBlk->block_cache_mutex); + continue; + } + + if((bytes = msBlk->block_cache[i].length - offset) >= length) { + if(buffer) + memcpy(buffer, msBlk->block_cache[i].data + offset, length); + if(msBlk->block_cache[i].length - offset == length) { + *next_block = msBlk->block_cache[i].next_index; + *next_offset = 0; + } else { + *next_block = block; + *next_offset = offset + length; + } + + up(&msBlk->block_cache_mutex); + return return_length; + } else { + if(buffer) { + memcpy(buffer, msBlk->block_cache[i].data + offset, bytes); + buffer += bytes; + } + block = msBlk->block_cache[i].next_index; + up(&msBlk->block_cache_mutex); + length -= bytes; + offset = 0; + } + } +} + + +static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); + squashfs_fragment_entry fragment_entry; + + if(msBlk->swap) { + squashfs_fragment_entry sfragment_entry; + + if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset, + sizeof(sfragment_entry), &start_block, &offset)) + return 0; + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); + } else + if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset, + sizeof(fragment_entry), &start_block, &offset)) + return 0; + + *fragment_start_block = fragment_entry.start_block; + *fragment_size = fragment_entry.size; + + return 1; +} + + +void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment) +{ + down(&msBlk->fragment_mutex); + fragment->locked --; + wake_up(&msBlk->fragment_wait_queue); + up(&msBlk->fragment_mutex); +} + + +struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length) +{ + int i, n; + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + + for(;;) { + down(&msBlk->fragment_mutex); + for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++); + if(i == SQUASHFS_CACHED_FRAGMENTS) { + for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS; + n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS); + + if(n == 0) { + wait_queue_t wait; + + init_waitqueue_entry(&wait, current); + add_wait_queue(&msBlk->fragment_wait_queue, &wait); + up(&msBlk->fragment_mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&msBlk->fragment_wait_queue, &wait); + continue; + } + msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS; + + if(msBlk->fragment[i].data == NULL) + if(!(msBlk->fragment[i].data = (unsigned char *) + SQUASHFS_ALLOC(SQUASHFS_FILE_MAX_SIZE))) { + ERROR("Failed to allocate fragment cache block\n"); + up(&msBlk->fragment_mutex); + return NULL; + } + + msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; + msBlk->fragment[i].locked = 1; + up(&msBlk->fragment_mutex); + if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length, + NULL))) { + ERROR("Unable to read fragment cache block [%x]\n", start_block); + msBlk->fragment[i].locked = 0; + return NULL; + } + msBlk->fragment[i].block = start_block; + TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); + return &msBlk->fragment[i]; + } + + msBlk->fragment[i].locked ++; + up(&msBlk->fragment_mutex); + + TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); + return &msBlk->fragment[i]; + } +} + + +#ifdef SQUASHFS_1_0_COMPATIBILITY +static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode) +{ + struct inode *i = new_inode(s); + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + unsigned int next_block, next_offset; + squashfs_base_inode_header_1 inodeb; + + TRACE("Entered squashfs_iget_1\n"); + + if(msBlk->swap) { + squashfs_base_inode_header_1 sinodeb; + + if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, + sizeof(sinodeb), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb)); + } else + if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, + sizeof(inodeb), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = 1; + + i->i_mtime.tv_sec = sBlk->mkfs_time; + i->i_atime.tv_sec = sBlk->mkfs_time; + i->i_ctime.tv_sec = sBlk->mkfs_time; + + if(inodeb.inode_type != SQUASHFS_IPC_TYPE) + i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; + i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); + + i->i_mode = inodeb.mode; + + switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) { + case SQUASHFS_FILE_TYPE: { + squashfs_reg_inode_header_1 inodep; + + if(msBlk->swap) { + squashfs_reg_inode_header_1 sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.file_size; + i->i_fop = &generic_ro_fops; + if(sBlk->block_size > 4096) + i->i_data.a_ops = &squashfs_aops; + else if(sBlk->block_size == 4096) + i->i_data.a_ops = &squashfs_aops_4K; + else + i->i_data.a_ops = &squashfs_aops_lessthan4K; + i->i_mode |= S_IFREG; + i->i_mtime.tv_sec = inodep.mtime; + i->i_atime.tv_sec = inodep.mtime; + i->i_ctime.tv_sec = inodep.mtime; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + SQUASHFS_I(i)->u.s1.fragment_start_block = SQUASHFS_INVALID_BLK; + SQUASHFS_I(i)->u.s1.fragment_offset = 0; + SQUASHFS_I(i)->start_block = inodep.start_block; + SQUASHFS_I(i)->block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); + break; + } + case SQUASHFS_DIR_TYPE: { + squashfs_dir_inode_header_1 inodep; + + if(msBlk->swap) { + squashfs_dir_inode_header_1 sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + i->i_mtime.tv_sec = inodep.mtime; + i->i_atime.tv_sec = inodep.mtime; + i->i_ctime.tv_sec = inodep.mtime; + SQUASHFS_I(i)->start_block = inodep.start_block; + SQUASHFS_I(i)->offset = inodep.offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, + inodep.start_block, inodep.offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { + squashfs_symlink_inode_header_1 inodep; + + if(msBlk->swap) { + squashfs_symlink_inode_header_1 sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.symlink_size; + i->i_op = &page_symlink_inode_operations; + i->i_data.a_ops = &squashfs_symlink_aops; + i->i_mode |= S_IFLNK; + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + squashfs_dev_inode_header_1 inodep; + + if(msBlk->swap) { + squashfs_dev_inode_header_1 sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = 0; + i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; + init_special_inode(i, i->i_mode, old_decode_dev(inodep.rdev)); + TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); + break; + } + case SQUASHFS_IPC_TYPE: { + squashfs_ipc_inode_header_1 inodep; + + if(msBlk->swap) { + squashfs_ipc_inode_header_1 sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = 0; + i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; + i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid]; + init_special_inode(i, i->i_mode, 0); + break; + } + default: + ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); + goto failed_read1; + } + + if(inodeb.guid == 15) + i->i_gid = i->i_uid; + else + i->i_gid = msBlk->guid[inodeb.guid]; + + insert_inode_hash(i); + return i; + +failed_read: + ERROR("Unable to read inode [%x:%x]\n", block, offset); + +failed_read1: + return NULL; +} +#endif + + +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode) +{ + struct inode *i = new_inode(s); + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + unsigned int next_block, next_offset; + squashfs_base_inode_header inodeb; + + TRACE("Entered squashfs_iget\n"); + + if(msBlk->swap) { + squashfs_base_inode_header sinodeb; + + if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, + sizeof(sinodeb), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb)); + } else + if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, + sizeof(inodeb), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = 1; + + i->i_mtime.tv_sec = sBlk->mkfs_time; + i->i_atime.tv_sec = sBlk->mkfs_time; + i->i_ctime.tv_sec = sBlk->mkfs_time; + + i->i_uid = msBlk->uid[inodeb.uid]; + i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); + + i->i_mode = inodeb.mode; + + switch(inodeb.inode_type) { + case SQUASHFS_FILE_TYPE: { + squashfs_reg_inode_header inodep; + + if(msBlk->swap) { + squashfs_reg_inode_header sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + SQUASHFS_I(i)->u.s1.fragment_start_block = SQUASHFS_INVALID_BLK; + if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment, + &SQUASHFS_I(i)->u.s1.fragment_start_block, &SQUASHFS_I(i)->u.s1.fragment_size)) + goto failed_read; + + SQUASHFS_I(i)->u.s1.fragment_offset = inodep.offset; + i->i_size = inodep.file_size; + i->i_fop = &generic_ro_fops; + if(sBlk->block_size > 4096) + i->i_data.a_ops = &squashfs_aops; + else + i->i_data.a_ops = &squashfs_aops_4K; + i->i_mode |= S_IFREG; + i->i_mtime.tv_sec = inodep.mtime; + i->i_atime.tv_sec = inodep.mtime; + i->i_ctime.tv_sec = inodep.mtime; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + SQUASHFS_I(i)->start_block = inodep.start_block; + SQUASHFS_I(i)->block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); + break; + } + case SQUASHFS_DIR_TYPE: { + squashfs_dir_inode_header inodep; + + if(msBlk->swap) { + squashfs_dir_inode_header sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + i->i_mtime.tv_sec = inodep.mtime; + i->i_atime.tv_sec = inodep.mtime; + i->i_ctime.tv_sec = inodep.mtime; + SQUASHFS_I(i)->start_block = inodep.start_block; + SQUASHFS_I(i)->offset = inodep.offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, + inodep.start_block, inodep.offset); + break; + } + case SQUASHFS_LDIR_TYPE: { + squashfs_ldir_inode_header inodep; + + if(msBlk->swap) { + squashfs_ldir_inode_header sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LDIR_INODE_HEADER(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + i->i_mtime.tv_sec = inodep.mtime; + i->i_atime.tv_sec = inodep.mtime; + i->i_ctime.tv_sec = inodep.mtime; + SQUASHFS_I(i)->start_block = inodep.start_block; + SQUASHFS_I(i)->offset = inodep.offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; + SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; + SQUASHFS_I(i)->u.s2.directory_index_count = inodep.i_count; + TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, + inodep.start_block, inodep.offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { + squashfs_symlink_inode_header inodep; + + if(msBlk->swap) { + squashfs_symlink_inode_header sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = inodep.symlink_size; + i->i_op = &page_symlink_inode_operations; + i->i_data.a_ops = &squashfs_symlink_aops; + i->i_mode |= S_IFLNK; + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + squashfs_dev_inode_header inodep; + + if(msBlk->swap) { + squashfs_dev_inode_header sinodep; + + if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), + &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep); + } else + if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), + &next_block, &next_offset)) + goto failed_read; + + i->i_size = 0; + i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; + init_special_inode(i, i->i_mode, old_decode_dev(inodep.rdev)); + TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); + break; + } + case SQUASHFS_FIFO_TYPE: + case SQUASHFS_SOCKET_TYPE: { + i->i_size = 0; + i->i_mode |= (inodeb.inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; + init_special_inode(i, i->i_mode, 0); + break; + } + default: + ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); + goto failed_read1; + } + + if(inodeb.guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msBlk->guid[inodeb.guid]; + + insert_inode_hash(i); + return i; + +failed_read: + ERROR("Unable to read inode [%x:%x]\n", block, offset); + +failed_read1: + return NULL; +} + + +static int squashfs_fill_super(struct super_block *s, + void *data, int silent) +{ + squashfs_sb_info *msBlk; + squashfs_super_block *sBlk; + int i; + char b[BDEVNAME_SIZE]; + + TRACE("Entered squashfs_read_superblock\n"); + + if(!(s->s_fs_info = (void *) kmalloc(sizeof(squashfs_sb_info), GFP_KERNEL))) { + ERROR("Failed to allocate superblock\n"); + return -ENOMEM; + } + msBlk = (squashfs_sb_info *) s->s_fs_info; + sBlk = &msBlk->sBlk; + + msBlk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); + msBlk->devblksize_log2 = ffz(~msBlk->devblksize); + + init_MUTEX(&msBlk->read_page_mutex); + init_MUTEX(&msBlk->block_cache_mutex); + init_MUTEX(&msBlk->fragment_mutex); + + init_waitqueue_head(&msBlk->waitq); + init_waitqueue_head(&msBlk->fragment_wait_queue); + + if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SERROR("unable to read superblock\n"); + goto failed_mount; + } + + /* Check it is a SQUASHFS superblock */ + msBlk->swap = 0; + if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) { + if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { + squashfs_super_block sblk; + WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(s->s_bdev, b)); + SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); + memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); + msBlk->swap = 1; + } else { + SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(s->s_bdev, b)); + goto failed_mount; + } + } + + /* Check the MAJOR & MINOR versions */ +#ifdef SQUASHFS_1_0_COMPATIBILITY + if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) { + SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n", + sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR); + goto failed_mount; + } + if(sBlk->s_major == 1) + sBlk->block_size = sBlk->block_size_1; +#else + if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { + SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n", + sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); + goto failed_mount; + } +#endif + + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); + TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); + TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); + TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); + TRACE("Filesystem size %d bytes\n", sBlk->bytes_used); + TRACE("Block size %d\n", sBlk->block_size); + TRACE("Number of inodes %d\n", sBlk->inodes); + if(sBlk->s_major > 1) + TRACE("Number of fragments %d\n", sBlk->fragments); + TRACE("Number of uids %d\n", sBlk->no_uids); + TRACE("Number of gids %d\n", sBlk->no_guids); + TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); + TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); + if(sBlk->s_major > 1) + TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); + TRACE("sBlk->uid_start %x\n", sBlk->uid_start); + + s->s_flags |= MS_RDONLY; + s->s_op = &squashfs_ops; + + /* Init inode_table block pointer array */ + if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { + ERROR("Failed to allocate block cache\n"); + goto failed_mount; + } + + for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) + msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK; + + msBlk->next_cache = 0; + + /* Allocate read_data block */ + msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size; + if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) { + ERROR("Failed to allocate read_data block\n"); + goto failed_mount1; + } + + /* Allocate read_page block */ + if(sBlk->block_size > PAGE_CACHE_SIZE) { + if(!(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) { + ERROR("Failed to allocate read_page block\n"); + goto failed_mount2; + } + } else + msBlk->read_page = NULL; + + /* Allocate uid and gid tables */ + if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids + + sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) { + ERROR("Failed to allocate uid/gid table\n"); + goto failed_mount3; + } + msBlk->guid = msBlk->uid + sBlk->no_uids; + + if(msBlk->swap) { + squashfs_uid suid[sBlk->no_uids + sBlk->no_guids]; + + if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * + sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SERROR("unable to read uid/gid table\n"); + goto failed_mount4; + } + SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8)); + } else + if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * + sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SERROR("unable to read uid/gid table\n"); + goto failed_mount4; + } + + +#ifdef SQUASHFS_1_0_COMPATIBILITY + if(sBlk->s_major == 1) { + msBlk->iget = squashfs_iget_1; + msBlk->read_blocklist = read_blocklist_1; + msBlk->fragment = NULL; + msBlk->fragment_index = NULL; + goto allocate_root; + } +#endif + msBlk->iget = squashfs_iget; + msBlk->read_blocklist = read_blocklist; + + if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { + ERROR("Failed to allocate fragment block cache\n"); + goto failed_mount4; + } + + for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { + msBlk->fragment[i].locked = 0; + msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; + msBlk->fragment[i].data = NULL; + } + + msBlk->next_fragment = 0; + + /* Allocate fragment index table */ + if(!(msBlk->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) { + ERROR("Failed to allocate uid/gid table\n"); + goto failed_mount5; + } + + if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) && + !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start, + SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SERROR("unable to read fragment index table\n"); + goto failed_mount6; + } + + if(msBlk->swap) { + int i; + squashfs_fragment_index fragment; + + for(i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); i++) { + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msBlk->fragment_index[i], 1); + msBlk->fragment_index[i] = fragment; + } + } + +#ifdef SQUASHFS_1_0_COMPATIBILITY +allocate_root: +#endif + if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) { + ERROR("Root inode create failed\n"); + goto failed_mount5; + } + + TRACE("Leaving squashfs_read_super\n"); + return 0; + +failed_mount6: + kfree(msBlk->fragment_index); +failed_mount5: + kfree(msBlk->fragment); +failed_mount4: + kfree(msBlk->uid); +failed_mount3: + kfree(msBlk->read_page); +failed_mount2: + kfree(msBlk->read_data); +failed_mount1: + kfree(msBlk->block_cache); +failed_mount: + kfree(s->s_fs_info); + s->s_fs_info = NULL; + return -EINVAL; +} + + +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *s = dentry->d_sb; + squashfs_super_block *sBlk = &((squashfs_sb_info *)s->s_fs_info)->sBlk; + + TRACE("Entered squashfs_statfs\n"); + buf->f_type = SQUASHFS_MAGIC; + buf->f_bsize = sBlk->block_size; + buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1; + buf->f_bfree = buf->f_bavail = 0; + buf->f_files = sBlk->inodes; + buf->f_ffree = 0; + buf->f_namelen = SQUASHFS_NAME_LEN; + return 0; +} + + +static int squashfs_symlink_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + int index = page->index << PAGE_CACHE_SHIFT, length, bytes; + unsigned int block = SQUASHFS_I(inode)->start_block; + int offset = SQUASHFS_I(inode)->offset; + void *pageaddr = kmap(page); + + TRACE("Entered squashfs_symlink_readpage, page index %d, start block %x, offset %x\n", + page->index, SQUASHFS_I(inode)->start_block, SQUASHFS_I(inode)->offset); + + for(length = 0; length < index; length += bytes) { + if(!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, offset, + PAGE_CACHE_SIZE, &block, &offset))) { + ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); + goto skip_read; + } + } + + if(length != index) { + ERROR("(squashfs_symlink_readpage) length != index\n"); + bytes = 0; + goto skip_read; + } + + bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length; + if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset))) + ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); + +skip_read: + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + + return 0; +} + + +#define SIZE 256 + +#ifdef SQUASHFS_1_0_COMPATIBILITY +static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, + char *block_list, unsigned short **block_p, unsigned int *bsize) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; + unsigned short *block_listp; + int i = 0; + int block_ptr = SQUASHFS_I(inode)->block_list_start; + int offset = SQUASHFS_I(inode)->offset; + unsigned int block = SQUASHFS_I(inode)->start_block; + + for(;;) { + int blocks = (index + readahead_blks - i); + if(blocks > (SIZE >> 1)) { + if((index - i) <= (SIZE >> 1)) + blocks = index - i; + else + blocks = SIZE >> 1; + } + + if(msBlk->swap) { + unsigned char sblock_list[SIZE]; + if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); + return 0; + } + SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks); + } else + if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); + return 0; + } + for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) + block += SQUASHFS_COMPRESSED_SIZE(*block_listp); + if(blocks >= readahead_blks) + break; + } + + if(bsize) + *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0); + else + *block_p = block_listp; + return block; +} +#endif + + +static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, + char *block_list, unsigned short **block_p, unsigned int *bsize) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; + unsigned int *block_listp; + int i = 0; + int block_ptr = SQUASHFS_I(inode)->block_list_start; + int offset = SQUASHFS_I(inode)->offset; + unsigned int block = SQUASHFS_I(inode)->start_block; + + for(;;) { + int blocks = (index + readahead_blks - i); + if(blocks > (SIZE >> 2)) { + if((index - i) <= (SIZE >> 2)) + blocks = index - i; + else + blocks = SIZE >> 2; + } + + if(msBlk->swap) { + unsigned char sblock_list[SIZE]; + if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); + return 0; + } + SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks); + } else + if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { + ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); + return 0; + } + for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); + if(blocks >= readahead_blks) + break; + } + + *bsize = *block_listp; + return block; +} + + +static int squashfs_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + unsigned char block_list[SIZE]; + unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0; + int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT); + void *pageaddr = kmap(page); + struct squashfs_fragment_cache *fragment = NULL; + char *data_ptr = msBlk->read_page; + + int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1; + int start_index = page->index & ~mask; + int end_index = start_index | mask; + + TRACE("Entered squashfs_readpage, page index %x, start block %x\n", (unsigned int) page->index, + SQUASHFS_I(inode)->start_block); + + if(page->index >= ((inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { + goto skip_read; + } + + if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) { + if((block = (msBlk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize)) == 0) + goto skip_read; + + down(&msBlk->read_page_mutex); + if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, bsize, NULL))) { + ERROR("Unable to read page, block %x, size %x\n", block, bsize); + up(&msBlk->read_page_mutex); + goto skip_read; + } + } else { + if((fragment = get_cached_fragment(inode->i_sb, SQUASHFS_I(inode)->u.s1.fragment_start_block, SQUASHFS_I(inode)->u.s1.fragment_size)) == NULL) { + ERROR("Unable to read page, block %x, size %x\n", SQUASHFS_I(inode)->u.s1.fragment_start_block, (int) SQUASHFS_I(inode)->u.s1.fragment_size); + goto skip_read; + } + bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + (inode->i_size & (sBlk->block_size - 1)); + byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset; + data_ptr = fragment->data; + } + + for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) { + struct page *push_page; + int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset; + + TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes); + + if(i == page->index) { + memcpy(pageaddr, data_ptr + byte_offset, available_bytes); + memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + } else if((push_page = grab_cache_page_nowait(page->mapping, i))) { + void *pageaddr = kmap(push_page); + memcpy(pageaddr, data_ptr + byte_offset, available_bytes); + memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); + kunmap(push_page); + flush_dcache_page(push_page); + SetPageUptodate(push_page); + unlock_page(push_page); + page_cache_release(push_page); + } + } + + if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) + up(&msBlk->read_page_mutex); + else + release_cached_fragment(msBlk, fragment); + + return 0; + +skip_read: + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + + return 0; +} + + +static int squashfs_readpage4K(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + unsigned char block_list[SIZE]; + unsigned int bsize, block, bytes = 0; + void *pageaddr = kmap(page); + + TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index, + SQUASHFS_I(inode)->start_block); + + if(page->index >= ((inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { + goto skip_read; + } + + if(SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK || page->index < (inode->i_size >> sBlk->block_log)) { + block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); + + if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, NULL))) + ERROR("Unable to read page, block %x, size %x\n", block, bsize); + } else { + struct squashfs_fragment_cache *fragment; + + if((fragment = get_cached_fragment(inode->i_sb, SQUASHFS_I(inode)->u.s1.fragment_start_block, SQUASHFS_I(inode)->u.s1.fragment_size)) == NULL) + ERROR("Unable to read page, block %x, size %x\n", SQUASHFS_I(inode)->u.s1.fragment_start_block, (int) SQUASHFS_I(inode)->u.s1.fragment_size); + else { + bytes = inode->i_size & (sBlk->block_size - 1); + memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset, bytes); + release_cached_fragment(msBlk, fragment); + } + } + +skip_read: + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + + return 0; +} + + +#ifdef SQUASHFS_1_0_COMPATIBILITY +static int squashfs_readpage_lessthan4K(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + squashfs_sb_info *msBlk = (squashfs_sb_info *)inode->i_sb->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + unsigned char block_list[SIZE]; + unsigned short *block_listp, block, bytes = 0; + int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log); + int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1; + int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log); + void *pageaddr = kmap(page); + + int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log)); + int byte; + + TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index, + SQUASHFS_I(inode)->start_block); + + block = read_blocklist_1(inode, index, readahead_blks, block_list, &block_listp, NULL); + + if(i_end > file_blocks) + i_end = file_blocks; + + while(index < i_end) { + int c_byte = !SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_SIZE(*block_listp) | SQUASHFS_COMPRESSED_BIT_BLOCK : *block_listp; + if(!(byte = read_data(inode->i_sb, pageaddr, block, c_byte, NULL))) { + ERROR("Unable to read page, block %x, size %x\n", block, *block_listp); + goto skip_read; + } + block += SQUASHFS_COMPRESSED_SIZE(*block_listp); + pageaddr += byte; + bytes += byte; + index ++; + block_listp ++; + } + +skip_read: + memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + + return 0; +} +#endif + + +static int get_dir_index_using_offset(struct super_block *s, unsigned int *next_block, + unsigned int *next_offset, unsigned int index_start, unsigned int index_offset, + int i_count, long long f_pos) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + int i, length = 0; + squashfs_dir_index index; + + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", i_count, (unsigned int) f_pos); + + if(f_pos == 0) + return 0; + + for(i = 0; i < i_count; i++) { + if(msBlk->swap) { + squashfs_dir_index sindex; + squashfs_get_cached_block(s, (char *) &sindex, index_start, index_offset, + sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else + squashfs_get_cached_block(s, (char *) &index, index_start, index_offset, + sizeof(index), &index_start, &index_offset); + + if(index.index > f_pos) + break; + + squashfs_get_cached_block(s, NULL, index_start, index_offset, + index.size + 1, &index_start, &index_offset); + + length = index.index; + *next_block = index.start_block + sBlk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + return length; +} + + +static int get_dir_index_using_name(struct super_block *s, unsigned int *next_block, + unsigned int *next_offset, unsigned int index_start, unsigned int index_offset, + int i_count, const char *name, int size) +{ + squashfs_sb_info *msBlk = (squashfs_sb_info *)s->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + int i, length = 0; + char buffer[sizeof(squashfs_dir_index) + SQUASHFS_NAME_LEN + 1]; + squashfs_dir_index *index = (squashfs_dir_index *) buffer; + char str[SQUASHFS_NAME_LEN + 1]; + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + + if (size > SQUASHFS_NAME_LEN) { + ERROR("Filename length %d > SQUASHFS_NAME_LEN\n", size); + size = SQUASHFS_NAME_LEN; + } + + strncpy(str, name, size); + str[size] = '\0'; + + for(i = 0; i < i_count; i++) { + if(msBlk->swap) { + squashfs_dir_index sindex; + squashfs_get_cached_block(s, (char *) &sindex, index_start, index_offset, + sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(index, &sindex); + } else + squashfs_get_cached_block(s, (char *) index, index_start, index_offset, + sizeof(squashfs_dir_index), &index_start, &index_offset); + + squashfs_get_cached_block(s, index->name, index_start, index_offset, + index->size + 1, &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + + if(strcmp(index->name, str) > 0) + break; + + length = index->index; + *next_block = index->start_block + sBlk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + return length; +} + + +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + struct inode *i = file->f_dentry->d_inode; + squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = + SQUASHFS_I(i)->offset, length = 0, dirs_read = 0, dir_count; + squashfs_dir_header dirh; + char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; + squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; + + TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset); + + lock_kernel(); + + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); + + while(length < i->i_size) { + /* read directory header */ + if(msBlk->swap) { + squashfs_dir_header sdirh; + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, + next_offset, sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { + if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, + next_offset, sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while(dir_count--) { + if(msBlk->swap) { + squashfs_dir_entry sdire; + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block, + next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { + if(!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block, + next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + length += sizeof(*dire); + } + + if(!squashfs_get_cached_block(i->i_sb, dire->name, next_block, + next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + length += dire->size + 1; + + if(file->f_pos >= length) + continue; + + dire->name[dire->size + 1] = '\0'; + + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent, + dire->name, dire->size + 1, (int) file->f_pos, + dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]); + + if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block, + dire->offset), squashfs_filetype_table[dire->type]) < 0) { + TRACE("Filldir returned less than 0\n"); + unlock_kernel(); + return dirs_read; + } + + file->f_pos = length; + dirs_read ++; + } + } + + unlock_kernel(); + return dirs_read; + +failed_read: + unlock_kernel(); + ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); + return 0; +} + + +static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, struct nameidata *nd) +{ + const unsigned char *name =dentry->d_name.name; + int len = dentry->d_name.len; + struct inode *inode = NULL; + squashfs_sb_info *msBlk = (squashfs_sb_info *)i->i_sb->s_fs_info; + squashfs_super_block *sBlk = &msBlk->sBlk; + int next_block = SQUASHFS_I(i)->start_block + sBlk->directory_table_start, next_offset = + SQUASHFS_I(i)->offset, length = 0, dir_count; + squashfs_dir_header dirh; + char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN]; + squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; + int squashfs_2_1 = sBlk->s_major == 2 && sBlk->s_minor == 1; + + TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset); + + if (len > SQUASHFS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + + lock_kernel(); + + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, SQUASHFS_I(i)->u.s2.directory_index_count, name, len); + + while(length < i->i_size) { + /* read directory header */ + if(msBlk->swap) { + squashfs_dir_header sdirh; + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, + sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { + if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, + sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while(dir_count--) { + if(msBlk->swap) { + squashfs_dir_entry sdire; + if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, + next_block,next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { + if(!squashfs_get_cached_block(i->i_sb, (char *) dire, + next_block,next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + length += sizeof(*dire); + } + + if(!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + length += dire->size + 1; + + if(squashfs_2_1 && name[0] < dire->name[0]) + goto exit_loop; + + if((len == dire->size + 1) && !strncmp(name, dire->name, len)) { + squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); + + TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n", + name, dirh.start_block, dire->offset); + + inode = (msBlk->iget)(i->i_sb, ino); + + goto exit_loop; + } + } + } + +exit_loop: + d_add(dentry, inode); + unlock_kernel(); + return ERR_PTR(0); + +failed_read: + ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); + goto exit_loop; +} + + +static void squashfs_put_super(struct super_block *s) +{ + int i; + + if(s->s_fs_info) { + squashfs_sb_info *sbi = (squashfs_sb_info *) s->s_fs_info; + if(sbi->block_cache) { + for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) + if(sbi->block_cache[i].block != SQUASHFS_INVALID_BLK) + kfree(sbi->block_cache[i].data); + kfree(sbi->block_cache); + } + if(sbi->read_data) kfree(sbi->read_data); + if(sbi->read_page) kfree(sbi->read_page); + if(sbi->uid) kfree(sbi->uid); + if(sbi->fragment) { + for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) + if(sbi->fragment[i].data != NULL) + SQUASHFS_FREE(sbi->fragment[i].data); + kfree(sbi->fragment); + } + if(sbi->fragment_index) kfree(sbi->fragment_index); + kfree(s->s_fs_info); + s->s_fs_info = NULL; + } +} + + +static int squashfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, mnt); +} + + +static int __init init_squashfs_fs(void) +{ + int err = init_inodecache(); + if(err) + return err; + + printk(KERN_INFO "Squashfs 2.2-r2 (released 2005/09/08) (C) 2002-2005 Phillip Lougher\n"); + +#ifdef CONFIG_SQUASHFS_LZMA + printk(KERN_INFO "Squashfs 2.2 includes LZMA decompression support\n"); + if(!(lzma_data = (char *) vmalloc(lzma_workspace_size()))) { + ERROR("Failed to allocate lzma workspace\n"); + return -ENOMEM; + } + lzma_init(lzma_data, lzma_workspace_size()); +#else + if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { + ERROR("Failed to allocate zlib workspace\n"); + destroy_inodecache(); + return -ENOMEM; + } +#endif + + if((err = register_filesystem(&squashfs_fs_type))) { +#ifndef CONFIG_SQUASHFS_LZMA + vfree(stream.workspace); +#endif + destroy_inodecache(); + } + + return err; +} + + +static void __exit exit_squashfs_fs(void) +{ +#ifdef CONFIG_SQUASHFS_LZMA + vfree(lzma_data); +#else + vfree(stream.workspace); +#endif + unregister_filesystem(&squashfs_fs_type); + destroy_inodecache(); +} + + +static kmem_cache_t * squashfs_inode_cachep; + + +static struct inode *squashfs_alloc_inode(struct super_block *sb) +{ + struct squashfs_inode_info *ei; + ei = (struct squashfs_inode_info *)kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL); + if (!ei) + return NULL; + return &ei->vfs_inode; +} + + +static void squashfs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); +} + + +static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +{ + struct squashfs_inode_info *ei = (struct squashfs_inode_info *) foo; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(&ei->vfs_inode); +} + + +static int init_inodecache(void) +{ + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", + sizeof(struct squashfs_inode_info), + 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + init_once, NULL); + if (squashfs_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + + +static void destroy_inodecache(void) +{ + kmem_cache_destroy(squashfs_inode_cachep); +} + + +module_init(init_squashfs_fs); +module_exit(exit_squashfs_fs); +MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); +MODULE_AUTHOR("Phillip Lougher "); +MODULE_LICENSE("GPL"); diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 09360cf1..ff4f62a1 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1319,6 +1319,7 @@ xfs_get_blocks( bh_result, create, 0, BMAPI_WRITE); } +#ifdef CONFIG_DIRECTIO STATIC int xfs_get_blocks_direct( struct inode *inode, @@ -1407,6 +1408,7 @@ xfs_vm_direct_IO( xfs_destroy_ioend(iocb->private); return ret; } +#endif STATIC int xfs_vm_prepare_write( @@ -1472,6 +1474,8 @@ const struct address_space_operations xfs_address_space_operations = { .prepare_write = xfs_vm_prepare_write, .commit_write = generic_commit_write, .bmap = xfs_vm_bmap, +#ifdef CONFIG_DIRECTIO .direct_IO = xfs_vm_direct_IO, +#endif .migratepage = buffer_migrate_page, }; diff --git a/include/asm-arm/arch-atmel/at91x40.h b/include/asm-arm/arch-atmel/at91x40.h new file mode 100644 index 00000000..0e94bd83 --- /dev/null +++ b/include/asm-arm/arch-atmel/at91x40.h @@ -0,0 +1,57 @@ +/* + ******************* AT91x40xxx ******************** + */ + +#define ARM_CLK CONFIG_ARM_CLK + +#define AT91_USART_CNT 2 +#define AT91_USART0_BASE (0xfffd0000) +#define AT91_USART1_BASE (0xfffcc000) +#define AT91_TC_BASE (0xfffe0000) +#define AIC_BASE (0xfffff000) +#define AT91_PIOA_BASE (0xffff0000) +#define AT91_SF_CIDR (0xfff00000) + +#define HARD_RESET_NOW() + +#define HW_AT91_TIMER_INIT(timer) /* no PMC */ + +/* use TC0 as hardware timer to create high resolution timestamps for debugging. + * Timer 0 must be set up as a free running counter, e.g. in the bootloader + */ +#define HW_COUNTER (((struct at91_timers *)AT91_TC_BASE)->chans[0].ch.cv) + +/* enable US0,US1 */ +#define HW_AT91_USART_INIT ((volatile struct pio_regs *)AT91_PIOA_BASE)->pdr = \ + PIOA_RXD0|PIOA_TXD0|PIOA_RXD1|PIOA_TXD1; +/* PIOA bit allocation */ +#define PIOA_TCLK0 (1<<0) +#define PIOA_TI0A0 (1<<1) +#define PIOA_TI0B0 (1<<2) +#define PIOA_TCLK1 (1<<3) +#define PIOA_TIOA1 (1<<4) +#define PIOA_TIOB1 (1<<5) +#define PIOA_TCLK2 (1<<6) +#define PIOA_TIOA2 (1<<7) +#define PIOA_TIOB2 (1<<8) +#define PIOA_IRQ0 (1<<9) +#define PIOA_IRQ1 (1<<10) +#define PIOA_IRQ2 (1<<11) +#define PIOA_FIQ (1<<12) +#define PIOA_SCK0 (1<<13) +#define PIOA_TXD0 (1<<14) +#define PIOA_RXD0 (1<<15) + +#define PIOA_SCK1 (1<<20) +#define PIOA_TXD1 (1<<21) +#define PIOA_RXD1 (1<<22) + +#define PIOA_MCK0 (1<<25) +#define PIOA_NCS2 (1<<26) +#define PIOA_NCS3 (1<<27) + +#define PIOA_A20_CS7 (1<<28) +#define PIOA_A21_CS6 (1<<29) +#define PIOA_A22_CS5 (1<<30) +#define PIOA_A23_CS4 (1<<31) + diff --git a/include/asm-arm/arch-atmel/at91x63.h b/include/asm-arm/arch-atmel/at91x63.h new file mode 100644 index 00000000..10586401 --- /dev/null +++ b/include/asm-arm/arch-atmel/at91x63.h @@ -0,0 +1,73 @@ +/* + ******************* AT91x63xxx ******************** + */ + +#define ARM_CLK CONFIG_ARM_CLK + +#define AT91_USART_CNT 2 +#define AT91_USART0_BASE (0xfffc0000) +#define AT91_USART1_BASE (0xfffc4000) +#define AT91_TC_BASE (0xfffd0000) +#define AIC_BASE (0xfffff000) +#define AT91_PIOA_BASE (0xfffec000) +#define AT91_PIOB_BASE (0xffff0000) +#define AT91_PMC_BASE (0xffff4000) + +/* enable US0,US1 */ +#define HW_AT91_USART_INIT ((volatile struct pmc_regs *)AT91_PMC_BASE)->pcer = \ + (1<<2) | (1<<3) | (1<<13); \ + ((volatile struct pio_regs *)AT91_PIOA_BASE)->pdr = \ + PIOA_RXD0|PIOA_TXD0|PIOA_RXD1|PIOA_TXD1; + +#define HW_AT91_TIMER_INIT(timer) ((volatile struct pmc_regs *)AT91_PMC_BASE)->pcer = \ + 1<<(timer+6); + +/* PIOA bit allocation */ +#define PIOA_TCLK3 (1<<0) +#define PIOA_TI0A3 (1<<1) +#define PIOA_TI0B3 (1<<2) +#define PIOA_TCLK4 (1<<3) +#define PIOA_TI0A4 (1<<4) +#define PIOA_TI0B4 (1<<5) +#define PIOA_TCLK5 (1<<6) +#define PIOA_TI0A5 (1<<7) +#define PIOA_TI0B5 (1<<8) +#define PIOA_IRQ0 (1<<9) +#define PIOA_IRQ1 (1<<10) +#define PIOA_IRQ2 (1<<11) +#define PIOA_IRQ3 (1<<12) +#define PIOA_FIQ (1<<13) +#define PIOA_SCK0 (1<<14) +#define PIOA_TXD0 (1<<15) +#define PIOA_RXD0 (1<<16) +#define PIOA_SCK1 (1<<17) +#define PIOA_TXD1 (1<<18) +#define PIOA_RXD1 (1<<19) +#define PIOA_SCK2 (1<<20) +#define PIOA_TXD2 (1<<21) +#define PIOA_RXD2 (1<<22) +#define PIOA_SPCK (1<<23) +#define PIOA_MISO (1<<24) +#define PIOA_MOSI (1<<25) +#define PIOA_NPCS0 (1<<26) +#define PIOA_NPCS1 (1<<27) +#define PIOA_NPCS2 (1<<28) +#define PIOA_NPCS3 (1<<29) + +/* PIOB bit allocation */ +#define PIOB_MPI_NOE (1<<0) +#define PIOB_MPI_NLB (1<<1) +#define PIOB_MPI_NUB (1<<2) + +#define PIOB_MCK0 (1<<17) +#define PIOB_BMS (1<<18) +#define PIOB_TCLK0 (1<<19) +#define PIOB_TIOA0 (1<<20) +#define PIOB_TIOB0 (1<<21) +#define PIOB_TCLK1 (1<<22) +#define PIOB_TIOA1 (1<<23) +#define PIOB_TIOB1 (1<<24) +#define PIOB_TCLK2 (1<<25) +#define PIOB_TIOA2 (1<<26) +#define PIOB_TIOB2 (1<<27) + diff --git a/include/asm-arm/arch-atmel/dma.h b/include/asm-arm/arch-atmel/dma.h new file mode 100644 index 00000000..8284a5fd --- /dev/null +++ b/include/asm-arm/arch-atmel/dma.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-arm/arch-atmel/dma.h + * + * Copyright (C) 2003 Hyok S. Choi + */ + +#include +#include + +#ifndef __ASM_ATMEL_ARCH_DMA_H +#define __ASM_ATMEL_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x01000000 +/* + * The atmel has 13 internal DMA channels. + */ +#define MAX_DMA_CHANNELS 13 +#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ + +#define arch_dma_init(dma_chan) +#endif /* _ASM_ATMEL_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-atmel/entry-macro.S b/include/asm-arm/arch-atmel/entry-macro.S new file mode 100644 index 00000000..8b91de8b --- /dev/null +++ b/include/asm-arm/arch-atmel/entry-macro.S @@ -0,0 +1,44 @@ +/* + * arch/armnommu/mach-atmel/entry-macro.S + * + * Copyright (C) 2003 Hyok S. Choi + * Samsung Electronics Co.,Ltd. + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + * 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 + +#if defined(CONFIG_ARCH_ATMEL) + .macro disable_fiq + .endm + /* r0 r6 r5 lr */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr r4, =AIC_IVR + ldr \irqnr, [r4] @ignore value + ldr r4, =AIC_ISR @read interrupt nr. + ldr \irqnr, [r4] + teq \irqnr, #0 + ldreq r4, =AIC_EOICR + streq r4, [r4] @acknowledge the spurious read of the IVR + .endm + + .macro irq_prio_table + .endm + +#endif diff --git a/include/asm-arm/arch-atmel/hardware.h b/include/asm-arm/arch-atmel/hardware.h new file mode 100644 index 00000000..89ca8789 --- /dev/null +++ b/include/asm-arm/arch-atmel/hardware.h @@ -0,0 +1,256 @@ +/* + * linux/include/asm-arm/arch-atmel/hardware.h + * + * for Atmel AT91 series + * 2001 Erwin Authried + * + * modified for linux 2.6 by Hyok S. Choi, 2004 + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +#ifndef __ASSEMBLY__ + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (1) + +#endif + +#define ATMEL_MEM_SIZE (CONFIG_DRAM_SIZE) +#define MEM_SIZE ATMEL_MEM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE + +/* 0=TC0, 1=TC1, 2=TC2 */ +#define KERNEL_TIMER 1 + +#ifdef CONFIG_CPU_AT91X40 +#include "at91x40.h" +#elif CONFIG_CPU_AT91X63 +#include "at91x63.h" +#else + #error "Configuration error: No CPU defined" +#endif + +/* + ******************* COMMON PART ******************** + */ +#define AIC_SMR(i) (AIC_BASE+i*4) +#define AIC_IVR (AIC_BASE+0x100) +#define AIC_FVR (AIC_BASE+0x104) +#define AIC_ISR (AIC_BASE+0x108) +#define AIC_IPR (AIC_BASE+0x10C) +#define AIC_IMR (AIC_BASE+0x110) +#define AIC_CISR (AIC_BASE+0x114) +#define AIC_IECR (AIC_BASE+0x120) +#define AIC_IDCR (AIC_BASE+0x124) +#define AIC_ICCR (AIC_BASE+0x128) +#define AIC_ISCR (AIC_BASE+0x12C) +#define AIC_EOICR (AIC_BASE+0x130) + + +#ifndef __ASSEMBLER__ +struct at91_timer_channel +{ + unsigned long ccr; // channel control register (WO) + unsigned long cmr; // channel mode register (RW) + unsigned long reserved[2]; + unsigned long cv; // counter value (RW) + unsigned long ra; // register A (RW) + unsigned long rb; // register B (RW) + unsigned long rc; // register C (RW) + unsigned long sr; // status register (RO) + unsigned long ier; // interrupt enable register (WO) + unsigned long idr; // interrupt disable register (WO) + unsigned long imr; // interrupt mask register (RO) +}; + +struct at91_timers +{ + struct { + struct at91_timer_channel ch; + unsigned char padding[0x40-sizeof(struct at91_timer_channel)]; + } chans[3]; + unsigned long bcr; // block control register (WO) + unsigned long bmr; // block mode register (RW) +}; +#endif + +/* TC control register */ +#define TC_SYNC (1) + +/* TC mode register */ +#define TC2XC2S(x) (x & 0x3) +#define TC1XC1S(x) (x<<2 & 0xc) +#define TC0XC0S(x) (x<<4 & 0x30) +#define TCNXCNS(timer,v) ((v) << (timer<<1)) + +/* TC channel control */ +#define TC_CLKEN (1) +#define TC_CLKDIS (1<<1) +#define TC_SWTRG (1<<2) + +/* TC interrupts enable/disable/mask and status registers */ +#define TC_MTIOB (1<<18) +#define TC_MTIOA (1<<17) +#define TC_CLKSTA (1<<16) + +#define TC_ETRGS (1<<7) +#define TC_LDRBS (1<<6) +#define TC_LDRAS (1<<5) +#define TC_CPCS (1<<4) +#define TC_CPBS (1<<3) +#define TC_CPAS (1<<2) +#define TC_LOVRS (1<<1) +#define TC_COVFS (1) + +/* + * USART registers + */ + + +/* US control register */ +#define US_SENDA (1<<12) +#define US_STTO (1<<11) +#define US_STPBRK (1<<10) +#define US_STTBRK (1<<9) +#define US_RSTSTA (1<<8) +#define US_TXDIS (1<<7) +#define US_TXEN (1<<6) +#define US_RXDIS (1<<5) +#define US_RXEN (1<<4) +#define US_RSTTX (1<<3) +#define US_RSTRX (1<<2) + +/* US mode register */ +#define US_CLK0 (1<<18) +#define US_MODE9 (1<<17) +#define US_CHMODE(x)(x<<14 & 0xc000) +#define US_NBSTOP(x)(x<<12 & 0x3000) +#define US_PAR(x) (x<<9 & 0xe00) +#define US_SYNC (1<<8) +#define US_CHRL(x) (x<<6 & 0xc0) +#define US_USCLKS(x)(x<<4 & 0x30) + +/* US interrupts enable/disable/mask and status register */ +#define US_DMSI (1<<10) +#define US_TXEMPTY (1<<9) +#define US_TIMEOUT (1<<8) +#define US_PARE (1<<7) +#define US_FRAME (1<<6) +#define US_OVRE (1<<5) +#define US_ENDTX (1<<4) +#define US_ENDRX (1<<3) +#define US_RXBRK (1<<2) +#define US_TXRDY (1<<1) +#define US_RXRDY (1) + +#define US_ALL_INTS (US_DMSI|US_TXEMPTY|US_TIMEOUT|US_PARE|US_FRAME|US_OVRE|US_ENDTX|US_ENDRX|US_RXBRK|US_TXRDY|US_RXRDY) + +#ifndef __ASSEMBLER__ +struct atmel_usart_regs{ + unsigned long cr; // control + unsigned long mr; // mode + unsigned long ier; // interrupt enable + unsigned long idr; // interrupt disable + unsigned long imr; // interrupt mask + unsigned long csr; // channel status + unsigned long rhr; // receive holding + unsigned long thr; // tramsmit holding + unsigned long brgr; // baud rate generator + unsigned long rtor; // rx time-out + unsigned long ttgr; // tx time-guard + unsigned long res1; + unsigned long rpr; // rx pointer + unsigned long rcr; // rx counter + unsigned long tpr; // tx pointer + unsigned long tcr; // tx counter +}; + +static inline void at91_usart_init(volatile struct atmel_usart_regs *uart, int baudrate) +{ + + uart->cr = US_TXDIS | US_RXDIS | US_RSTTX | US_RSTRX; + /* clear Rx receive and Tx sent counters */ + uart->rcr = 0; + uart->tcr = 0; + + uart->idr = US_TXEMPTY; /* tx disable */ + uart->idr = US_ENDRX | US_TIMEOUT; /* rx disable */ + + /* Set the serial port into a safe sane state */ + uart->mr = US_USCLKS(0) | US_CLK0 | US_CHMODE(0) | US_NBSTOP(0) | + US_PAR(4) | US_CHRL(3); + + /* FIXME: uart->brgr = ARM_CLK/16/baudrate; */ + uart->brgr = ARM_CLK/16/9600; + + uart->rtor = 20; // timeout = value * 4 *bit period + uart->ttgr = 0; // no guard time + uart->rcr = 0; + uart->rpr = 0; + uart->tcr = 0; + uart->tpr = 0; +#ifdef US_RTS + uart->mc = 0; +#endif +} + +static inline void at91_usart_putc(volatile struct atmel_usart_regs *uart, unsigned char c) +{ + uart->cr=US_TXEN; + uart->thr=c; + while(1) { + if (uart->csr & US_TXEMPTY) break; + } +} +#endif + +#define PIO(i) (1< +#include +#include +#include + + +#define fixup_irq(x) (x) + +extern void at91_mask_irq(unsigned int irq); +extern void at91_unmask_irq(unsigned int irq); +extern void at91_mask_ack_irq(unsigned int irq); + +#endif /* __ASM_ARCH_IRQ_H__ */ diff --git a/include/asm-arm/arch-atmel/irqs.h b/include/asm-arm/arch-atmel/irqs.h new file mode 100644 index 00000000..ffe4ec2a --- /dev/null +++ b/include/asm-arm/arch-atmel/irqs.h @@ -0,0 +1,65 @@ +/* + * linux/include/asm-arm/arch-atmel/irqs.h: + * 2001 Mindspeed + */ +#ifndef __ASM_ARCH_IRQS_H__ +#define __ASM_ARCH_IRQS_H__ + + +#ifdef CONFIG_CPU_AT91X40 +/* + ******************* AT91x40xxx ******************** + */ + +#define NR_IRQS 24 +#define VALID_IRQ(i) (i<=8 ||(i>=16 && i=28 && i + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((unsigned long) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((unsigned long) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-atmel/param.h b/include/asm-arm/arch-atmel/param.h new file mode 100644 index 00000000..8a1d92b2 --- /dev/null +++ b/include/asm-arm/arch-atmel/param.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-atmel/system.h b/include/asm-arm/arch-atmel/system.h new file mode 100644 index 00000000..1dac20e2 --- /dev/null +++ b/include/asm-arm/arch-atmel/system.h @@ -0,0 +1,42 @@ +/* + * linux/include/asm-arm/arch-atmel/system.h + * + * Copyright (C) 2002 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0); +} + +#endif diff --git a/include/asm-arm/arch-atmel/time.h b/include/asm-arm/arch-atmel/time.h new file mode 100644 index 00000000..01c007d6 --- /dev/null +++ b/include/asm-arm/arch-atmel/time.h @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-atmel/time.h + * + * Copyright (C) 2001/02 Erwin Authried + * Modified by Hyok S. Choi for 2.6, 2004. + */ + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ + +#include +#include +#include +#include + +#define CLOCKS_PER_USEC (CONFIG_ARM_CLK/1000000) + +#if (KERNEL_TIMER==0) +# define KERNEL_TIMER_IRQ_NUM IRQ_TC0 +#elif (KERNEL_TIMER==1) +# define KERNEL_TIMER_IRQ_NUM IRQ_TC1 +#elif (KERNEL_TIMER==2) +# define KERNEL_TIMER_IRQ_NUM IRQ_TC2 +#else +#error Wierd -- KERNEL_TIMER is not defined or something.... +#endif + +#endif + diff --git a/include/asm-arm/arch-atmel/timex.h b/include/asm-arm/arch-atmel/timex.h new file mode 100644 index 00000000..1555ab84 --- /dev/null +++ b/include/asm-arm/arch-atmel/timex.h @@ -0,0 +1,10 @@ +/* + * timex.h: + * 2001 Mindspeed + */ +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE 0x270f + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-atmel/uncompress.h b/include/asm-arm/arch-atmel/uncompress.h new file mode 100644 index 00000000..89c85c08 --- /dev/null +++ b/include/asm-arm/arch-atmel/uncompress.h @@ -0,0 +1,43 @@ +/* + * linux/include/asm-arm/arch-atmel/uncompress.h + * + * Copyright (C) 2006, Greg Ungerer + * Copyright (C) 2001 RidgeRun, Inc. (http://www.ridgerun.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 + */ + +#include + +static void putc(char c) +{ + static int inited = 0; + if (!inited) { + HW_AT91_USART_INIT + at91_usart_init((volatile struct atmel_usart_regs *) AT91_USART0_BASE, 9600); + inited = 1; + } + at91_usart_putc((volatile struct atmel_usart_regs *) AT91_USART0_BASE, c); +} + +static void flush(void) +{ +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-atmel/vmalloc.h b/include/asm-arm/arch-atmel/vmalloc.h new file mode 100644 index 00000000..e43e4826 --- /dev/null +++ b/include/asm-arm/arch-atmel/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-arm/arch-atmel/vmalloc.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_ATMEL_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_ATMEL_SDRAM_SIZE) diff --git a/include/asm-arm/arch-espd_4510b/dma.h b/include/asm-arm/arch-espd_4510b/dma.h new file mode 100644 index 00000000..62641c05 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/dma.h @@ -0,0 +1,28 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/dma.h + * + * Currently this is not used for the s3c4510b port + * + * Copyright (C) 2003 Hyok S. Choi + * + */ + +#include +#include + +#ifndef __ASM_S3C4510B_ARCH_DMA_H +#define __ASM_S3C4510B_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x03000000 +/* + * The S3C4510B has 2 internal DMA channels. + */ +#define MAX_DMA_CHANNELS 2 +#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ + +#endif /* __ASM_S3C4510B_ARCH_DMA_H */ + diff --git a/include/asm-arm/arch-espd_4510b/entry-macro.S b/include/asm-arm/arch-espd_4510b/entry-macro.S new file mode 100644 index 00000000..ec8c9f06 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/entry-macro.S @@ -0,0 +1,27 @@ +/* + * arch/armnommu/mach-espd_4510b/entry-macro.S + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + */ + +#if defined(CONFIG_ARCH_ESPD_4510B) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =REG_INTOSET_IRQ + ldr \irqnr, [\base] + mov \irqnr, \irqnr, lsr #2 + teq \irqnr, #NR_IRQS + .endm + + .macro irq_prio_table + .endm + +#endif diff --git a/include/asm-arm/arch-espd_4510b/hardware.h b/include/asm-arm/arch-espd_4510b/hardware.h new file mode 100644 index 00000000..d85d6120 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/hardware.h @@ -0,0 +1,30 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/hardware.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#ifndef __ASSEMBLY__ + +#define HARD_RESET_NOW() + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (1) + +#endif + +#endif /* END OF __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-espd_4510b/io.h b/include/asm-arm/arch-espd_4510b/io.h new file mode 100644 index 00000000..461fbaed --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/io.h @@ -0,0 +1,67 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/io.h + * + * Copyright (C) 2003 Thomas Eschenbacher + * Modified by Hyok S. Choi + * + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + /* Used in kernel/resource.c */ + +/* + * We have the this routine to use usb host device driver + */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + + +/* + * These macros were copied from arch/armnommu/io.h and are used instead + * of the definitions found there, because we want to do 16/32 bit i/o + * without byte swapping. + * --the + */ + +#undef __io + +#ifndef __iob + #define __iob(a) __io(a) +#endif + +#define outb(v,p) __raw_writeb(v, p) +#define outw(v,p) __raw_writew(v, p) +#define outl(v,p) __raw_writel(v, p) + +#define inb(p) ({ unsigned int __v = __raw_readb(p); __v; }) +#define inw(p) ({ unsigned int __v = __raw_readw(p); __v; }) +#define inl(p) ({ unsigned int __v = __raw_readl(p); __v; }) + +#define outsb(p,d,l) __raw_writesb(p, d, l) +#define outsw(p,d,l) __raw_writesw(p, d, l) +#define outsl(p,d,l) __raw_writesl(p, d, l) + +#define insb(p,d,l) __raw_readsb(p, d, l) +#define insw(p,d,l) __raw_readsw(p, d, l) +#define insl(p,d,l) __raw_readsl(p, d, l) + +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) (1) + + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-espd_4510b/irq.h b/include/asm-arm/arch-espd_4510b/irq.h new file mode 100644 index 00000000..34ba6cb9 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/irq.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/irq.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#ifndef __ARCH_S3C4510B_irq_h +#define __ARCH_S3C4510B_irq_h + +#include +#include +#include +#include + +extern unsigned int fixup_irq(int i); + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void s3c4510b_init_irq(void); + +#define irq_init_irq s3c4510b_init_irq + +#endif diff --git a/include/asm-arm/arch-espd_4510b/irqs.h b/include/asm-arm/arch-espd_4510b/irqs.h new file mode 100644 index 00000000..a1bbd58b --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/irqs.h @@ -0,0 +1,42 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/irqs.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * Based on: + * linux-2.4.x/asm/arch-samsung/irqs.h: + * Mac Wang + * + */ +#ifndef __ASM_ARCH_IRQS_H__ +#define __ASM_ARCH_IRQS_H__ +#define NR_IRQS 21 +#define VALID_IRQ(i) (i<=8 ||(i>=16 && i + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-espd_4510b/param.h b/include/asm-arm/arch-espd_4510b/param.h new file mode 100644 index 00000000..8a1d92b2 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/param.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-espd_4510b/s3c4510b.h b/include/asm-arm/arch-espd_4510b/s3c4510b.h new file mode 100644 index 00000000..4e593663 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/s3c4510b.h @@ -0,0 +1,255 @@ +#ifndef __HW_S3C4510_H +#define __HW_S3C4510_H + +/* + * linux/include/asm-armnommu/arch-espd_4510b/s3c4510b.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + * + * MODULE: $Id: s3c4510b.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * Description: Samsung S3C4510B register layout + * Runtime Env: ARM7TDMI + * Change History: + * 03-02-04 Create (Curt Brune) curt@cucy.com + */ + +/*------------------------------------------------------------------------ + * ASIC Address Definition + *----------------------------------------------------------------------*/ + + +#define S3C4510B_MEM_SIZE (CONFIG_DRAM_SIZE) +#define MEM_SIZE S3C4510B_MEM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE + +/* L1 8KB on chip SRAM base address */ +#define SRAM_BASE (0x03fe0000) + +/* Special Register Start Address After System Reset */ +#define REG_BASE (0x03ff0000) +#define SPSTR (REG_BASE) + +/* *********************** */ +/* System Manager Register */ +/* *********************** */ +#define REG_SYSCFG (REG_BASE+0x0000) + +#define REG_CLKCON (REG_BASE+0x3000) +#define REG_EXTACON0 (REG_BASE+0x3008) +#define REG_EXTACON1 (REG_BASE+0x300c) +#define REG_EXTDBWTH (REG_BASE+0x3010) +#define REG_ROMCON0 (REG_BASE+0x3014) +#define REG_ROMCON1 (REG_BASE+0x3018) +#define REG_ROMCON2 (REG_BASE+0x301c) +#define REG_ROMCON3 (REG_BASE+0x3020) +#define REG_ROMCON4 (REG_BASE+0x3024) +#define REG_ROMCON5 (REG_BASE+0x3028) +#define REG_DRAMCON0 (REG_BASE+0x302c) +#define REG_DRAMCON1 (REG_BASE+0x3030) +#define REG_DRAMCON2 (REG_BASE+0x3034) +#define REG_DRAMCON3 (REG_BASE+0x3038) +#define REG_REFEXTCON (REG_BASE+0x303c) + +/* *********************** */ +/* Ethernet BDMA Register */ +/* *********************** */ +#define REG_BDMATXCON (REG_BASE+0x9000) +#define REG_BDMARXCON (REG_BASE+0x9004) +#define REG_BDMATXPTR (REG_BASE+0x9008) +#define REG_BDMARXPTR (REG_BASE+0x900c) +#define REG_BDMARXLSZ (REG_BASE+0x9010) +#define REG_BDMASTAT (REG_BASE+0x9014) + +/* Content Address Memory */ +#define REG_CAM_BASE (REG_BASE+0x9100) + +#define REG_BDMATXBUF (REG_BASE+0x9200) +#define REG_BDMARXBUF (REG_BASE+0x9800) + +/* *********************** */ +/* Ethernet MAC Register */ +/* *********************** */ +#define REG_MACCON (REG_BASE+0xa000) +#define REG_CAMCON (REG_BASE+0xa004) +#define REG_MACTXCON (REG_BASE+0xa008) +#define REG_MACTXSTAT (REG_BASE+0xa00c) +#define REG_MACRXCON (REG_BASE+0xa010) +#define REG_MACRXSTAT (REG_BASE+0xa014) +#define REG_STADATA (REG_BASE+0xa018) +#define REG_STACON (REG_BASE+0xa01c) +#define REG_CAMEN (REG_BASE+0xa028) +#define REG_EMISSCNT (REG_BASE+0xa03c) +#define REG_EPZCNT (REG_BASE+0xa040) +#define REG_ERMPZCNT (REG_BASE+0xa044) +#define REG_ETXSTAT (REG_BASE+0x9040) +#define REG_MACRXDESTR (REG_BASE+0xa064) +#define REG_MACRXSTATEM (REG_BASE+0xa090) +#define REG_MACRXFIFO (REG_BASE+0xa200) + +/********************/ +/* I2C Bus Register */ +/********************/ +#define REG_I2C_CON (REG_BASE+0xf000) +#define REG_I2C_BUF (REG_BASE+0xf004) +#define REG_I2C_PS (REG_BASE+0xf008) +#define REG_I2C_COUNT (REG_BASE+0xf00c) + +/********************/ +/* GDMA 0 */ +/********************/ +#define REG_GDMACON0 (REG_BASE+0xb000) +#define REG_GDMA0_RUN_ENABLE (REG_BASE+0xb020) +#define REG_GDMASRC0 (REG_BASE+0xb004) +#define REG_GDMADST0 (REG_BASE+0xb008) +#define REG_GDMACNT0 (REG_BASE+0xb00c) + +/********************/ +/* GDMA 1 */ +/********************/ +#define REG_GDMACON1 (REG_BASE+0xc000) +#define REG_GDMA1_RUN_ENABLE (REG_BASE+0xc020) +#define REG_GDMASRC1 (REG_BASE+0xc004) +#define REG_GDMADST1 (REG_BASE+0xc008) +#define REG_GDMACNT1 (REG_BASE+0xc00c) + +#define UART_CNT (2) +/********************/ +/* UART 0 */ +/********************/ +#define UART0_BASE (REG_BASE+0xd000) +#define REG_UART0_LCON (REG_BASE+0xd000) +#define REG_UART0_CTRL (REG_BASE+0xd004) +#define REG_UART0_STAT (REG_BASE+0xd008) +#define REG_UART0_TXB (REG_BASE+0xd00c) +#define REG_UART0_RXB (REG_BASE+0xd010) +#define REG_UART0_BAUD_DIV (REG_BASE+0xd014) +#define REG_UART0_BAUD_CNT (REG_BASE+0xd018) +#define REG_UART0_BAUD_CLK (REG_BASE+0xd01C) + +/********************/ +/* UART 1 */ +/********************/ +#define UART1_BASE (REG_BASE+0xe000) +#define REG_UART1_LCON (REG_BASE+0xe000) +#define REG_UART1_CTRL (REG_BASE+0xe004) +#define REG_UART1_STAT (REG_BASE+0xe008) +#define REG_UART1_TXB (REG_BASE+0xe00c) +#define REG_UART1_RXB (REG_BASE+0xe010) +#define REG_UART1_BAUD_DIV (REG_BASE+0xe014) +#define REG_UART1_BAUD_CNT (REG_BASE+0xe018) +#define REG_UART1_BAUD_CLK (REG_BASE+0xe01C) + +/********************/ +/* Timer Register */ +/********************/ +#define REG_TMOD (REG_BASE+0x6000) +#define REG_TDATA0 (REG_BASE+0x6004) +#define REG_TDATA1 (REG_BASE+0x6008) +#define REG_TCNT0 (REG_BASE+0x600c) +#define REG_TCNT1 (REG_BASE+0x6010) + +/**********************/ +/* I/O Port Interface */ +/**********************/ +#define REG_IOPMODE (REG_BASE+0x5000) +#define REG_IOPCON (REG_BASE+0x5004) +#define REG_IOPDATA (REG_BASE+0x5008) + +/*********************************/ +/* Interrupt Controller Register */ +/*********************************/ +#define REG_INTMODE (REG_BASE+0x4000) +#define REG_INTPEND (REG_BASE+0x4004) +#define REG_INTMASK (REG_BASE+0x4008) + +#define REG_INTPRI0 (REG_BASE+0x400c) +#define REG_INTPRI1 (REG_BASE+0x4010) +#define REG_INTPRI2 (REG_BASE+0x4014) +#define REG_INTPRI3 (REG_BASE+0x4018) +#define REG_INTPRI4 (REG_BASE+0x401c) +#define REG_INTPRI5 (REG_BASE+0x4020) +#define REG_INTOFFSET (REG_BASE+0x4024) +#define REG_INTPNDPRI (REG_BASE+0x4028) +#define REG_INTPNDTST (REG_BASE+0x402C) +#define REG_INTOSET_FIQ (REG_BASE+0x4030) +#define REG_INTOSET_IRQ (REG_BASE+0x4034) + +#define INT_MODE_IRQ 0x000000 +#define INT_MODE_FIQ 0x1FFFFF +#define INT_MASK_DIS 0x1FFFFF +#define INT_MASK_ENA 0x000000 + +/*********************************/ +/* CACHE CONTROL MASKS */ +/*********************************/ +#define CACHE_STALL (0x00000001) +#define CACHE_ENABLE (0x00000002) +#define CACHE_WRITE_BUFF (0x00000004) +#define CACHE_MODE (0x00000030) +#define CACHE_MODE_00 (0x00000000) +#define CACHE_MODE_01 (0x00000010) +#define CACHE_MODE_10 (0x00000020) + +/*********************************/ +/* CACHE RAM BASE ADDRESSES */ +/*********************************/ +#define CACHE_SET0_RAM (0x10000000) +#define CACHE_SET1_RAM (0x10800000) +#define CACHE_TAG_RAM (0x11000000) + +/*********************************/ +/* CACHE_DISABLE MASK */ +/*********************************/ +#define CACHE_DISABLE_MASK (0x04000000) + +/*********************************************************/ +/* TIMER MODE REGISTER */ +/*********************************************************/ +#define TM0_RUN 0x01 /* Timer 0 enable */ +#define TM0_TOGGLE 0x02 /* 0, interval mode */ +#define TM0_OUT_1 0x04 /* Timer 0 Initial TOUT0 value */ +#define TM1_RUN 0x08 /* Timer 1 enable */ +#define TM1_TOGGLE 0x10 /* 0, interval mode */ +#define TM1_OUT_1 0x20 /* Timer 0 Initial TOUT0 value */ + +/********************************************************* + * INTERRUPT CONTROL + * + * An interrupt is enabled when mask bit is clear. + * An interrupt is disabled when mask bit is set. + *********************************************************/ +#define INT_ENABLE(n) outl( inl(REG_INTMASK) & ~( 1 << (n)), REG_INTMASK) +#define INT_DISABLE(n) outl( inl(REG_INTMASK) | ( 1 << (n)), REG_INTMASK) +#define CLEAR_PEND_INT(n) outl( (1 << (n)), REG_INTPEND) +#define SET_PEND_INT(n) outl( inl(REG_INTPNDTST) | ( 1 << (n)), REG_INTPNDMASK) + +#ifdef CONFIG_ARCH_ESPD_4510B +#define LED_SET(n) outl( inl(REG_IOPDATA) & ~(1<<(n)), REG_IOPDATA) +#define LED_CLR(n) outl( inl(REG_IOPDATA) | (1<<(n)), REG_IOPDATA) +#define LED_TOGGLE(n) outl( inl(REG_IOPDATA) ^ (1<<(n)), REG_IOPDATA) +#else +#define LED_SET(n) +#define LED_CLR(n) +#define LED_TOGGLE(n) +#endif + +#endif /* __S3C4510_h */ diff --git a/include/asm-arm/arch-espd_4510b/system.h b/include/asm-arm/arch-espd_4510b/system.h new file mode 100644 index 00000000..34765138 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/system.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/system.h + * + * Copyright (C) 2002 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +extern void __do_dump( const char *s); +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + printk(KERN_ERR"arch_reset() not implemented\n"); + BUG(); +} + +#endif diff --git a/include/asm-arm/arch-espd_4510b/time.h b/include/asm-arm/arch-espd_4510b/time.h new file mode 100644 index 00000000..d2311161 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/time.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/time.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * 2003 Thomas Eschenbacher + * modifed by Hyok S. Choi + * + * Setup for 32 bit timer 0, used as system timer. + * + * 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 + * + */ + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ + +#endif diff --git a/include/asm-arm/arch-espd_4510b/timex.h b/include/asm-arm/arch-espd_4510b/timex.h new file mode 100644 index 00000000..08eebdf7 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/timex.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/timex.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ + +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE (CONFIG_ARM_CLK) + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-espd_4510b/uart.h b/include/asm-arm/arch-espd_4510b/uart.h new file mode 100644 index 00000000..2605e7b6 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/uart.h @@ -0,0 +1,114 @@ +#ifndef _SC34510B_UART_H +#define _SC34510B_UART_H + +/* + * linux/include/asm-armnommu/arch-espd_4510b/uart.h + * + * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) + * Curt Brune + * + * 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 + * + * Description: S3C4510B UART register layout + * Runtime Env: ARM7TDMI + * Change History: + * 03-03-04 Create (Curt Brune) + */ + +/* UART LINE CONTROL register */ +typedef struct __BF_UART_LINE_CTRL { + u32 wordLen: 2; + u32 nStop: 1; + u32 parity: 3; + u32 clk: 1; + u32 infra_red: 1; + u32 unused:24; +} BF_UART_LINE_CTRL; + +typedef union _UART_LINE_CTRL { + u32 ui; + BF_UART_LINE_CTRL bf; +} UART_LINE_CTRL; + +/* UART CONTROL register */ +typedef struct __BF_UART_CTRL { + u32 rxMode: 2; + u32 rxIrq: 1; + u32 txMode: 2; + u32 DSR: 1; + u32 sendBreak: 1; + u32 loopBack: 1; + u32 unused:24; +} BF_UART_CTRL; + +typedef union _UART_CTRL { + u32 ui; + BF_UART_CTRL bf; +} UART_CTRL; + +/* UART STATUS register */ +typedef struct __BF_UART_STAT { + u32 overrun: 1; + u32 parity: 1; + u32 frame: 1; + u32 breakIrq: 1; + u32 DTR: 1; + u32 rxReady: 1; + u32 txBufEmpty: 1; + u32 txComplete: 1; + u32 unused:24; +} BF_UART_STAT; + +typedef union _UART_STAT { + u32 ui; + BF_UART_STAT bf; +} UART_STAT; + +/* UART BAUD_DIV register */ +typedef struct __BF_UART_BAUD_DIV { + u32 cnt1: 4; + u32 cnt0:12; + u32 unused:16; +} BF_UART_BAUD_DIV; + +typedef union _UART_BAUD_DIV { + u32 ui; + BF_UART_BAUD_DIV bf; +} UART_BAUD_DIV; + +/* UART register block */ +struct uart_regs { + volatile UART_LINE_CTRL m_lineCtrl; + volatile UART_CTRL m_ctrl; + volatile UART_STAT m_stat; + volatile u32 m_tx; + volatile u32 m_rx; + volatile UART_BAUD_DIV m_baudDiv; + volatile u32 m_baudCnt; + volatile u32 m_baudClk; +}; + +#define NL 0x0A +#define CR 0x0D +#define BSP 0x08 +#define ESC 0x1B +#define CTRLZ 0x1A +#define RUBOUT 0x7F + +#define UART_ANY_RX (0x2F) +#define UART_NR (2) + +#endif diff --git a/include/asm-arm/arch-espd_4510b/uncompress.c b/include/asm-arm/arch-espd_4510b/uncompress.c new file mode 100644 index 00000000..335f3638 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/uncompress.c @@ -0,0 +1,69 @@ +/* + * linux/include/asm/arch-samsung/uncompress.c + * 2001 Mac Wang + * + * linux-2.6.7/include/asm-armnommu/arch-espd_4510b/uncompress.c + * 2004 JS H. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +/* + * This is used by arch/armnommu/boot/compressed/misc.c to write progress info + * out the serial port so that the user can see debug messages up to the point + * where the kernel is decompressed. The STANDALONE_DEBUG macro chooses between + * this and the standard printf. Punt. + * --gmcnutt + */ +#define putstr(s) s3c4510b_puts(s) + +/* + * Not sure what this is for. Probably an optional watchdog to check if the + * decompress got hung so we can warn the user. Punt. + */ +#define arch_decomp_wdog() + +/* + * If we need to do some setup prior to decompression (like initializing the + * UART if we want to use puts() above) then we define it here. Punt. + */ +#define arch_decomp_setup() s3c4510b_decomp_setup() diff --git a/include/asm-arm/arch-espd_4510b/vmalloc.h b/include/asm-arm/arch-espd_4510b/vmalloc.h new file mode 100644 index 00000000..6b169d64 --- /dev/null +++ b/include/asm-arm/arch-espd_4510b/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/vmalloc.h + * + * Copyright (C) 2000 Russell King. + * modified by Hyok S. Choi + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_S3C4510_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_S3C4510_SDRAM_SIZE) diff --git a/include/asm-arm/arch-integrator/hardware.h b/include/asm-arm/arch-integrator/hardware.h index 6f0947bc..91c09f6b 100644 --- a/include/asm-arm/arch-integrator/hardware.h +++ b/include/asm-arm/arch-integrator/hardware.h @@ -25,19 +25,46 @@ #include #include +#ifndef CONFIG_MMU +#define MEM_SIZE CONFIG_DRAM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE +#endif + /* * Where in virtual memory the IO devices (timers, system controllers * and so on) */ +#ifdef CONFIG_MMU #define IO_BASE 0xF0000000 // VA of IO #define IO_SIZE 0x0B000000 // How much? #define IO_START INTEGRATOR_HDR_BASE // PA of IO +#endif + +/* + * Similar to above, but for PCI addresses (memory, IO, Config and the + * V3 chip itself). WARNING: this has to mirror definitions in platform.h + */ +#ifdef CONFIG_MMU +#define PCI_MEMORY_VADDR 0xe8000000 +#define PCI_CONFIG_VADDR 0xec000000 +#define PCI_V3_VADDR 0xed000000 +#define PCI_IO_VADDR 0xee000000 +#else +#define PCI_MEMORY_VADDR PHYS_PCI_MEM_BASE +#define PCI_CONFIG_VADDR PHYS_PCI_CONFIG_BASE +#define PCI_V3_VADDR PHYS_PCI_V3_BASE +#define PCI_IO_VADDR PHYS_PCI_IO_BASE +#endif #define PCIO_BASE PCI_IO_VADDR #define PCIMEM_BASE PCI_MEMORY_VADDR /* macro to get at IO space when running virtually */ +#ifdef CONFIG_MMU #define IO_ADDRESS(x) (((x) >> 4) + IO_BASE) +#else +#define IO_ADDRESS(x) (x) +#endif #define pcibios_assign_all_busses() 1 diff --git a/include/asm-arm/arch-integrator/memory.h b/include/asm-arm/arch-integrator/memory.h index 1ab56d78..37bd032b 100644 --- a/include/asm-arm/arch-integrator/memory.h +++ b/include/asm-arm/arch-integrator/memory.h @@ -24,6 +24,9 @@ * Physical DRAM offset. */ #define PHYS_OFFSET UL(0x00000000) + +#ifdef CONFIG_MMU + #define BUS_OFFSET UL(0x80000000) /* @@ -36,4 +39,11 @@ #define __virt_to_bus(x) (x - PAGE_OFFSET + BUS_OFFSET) #define __bus_to_virt(x) (x - BUS_OFFSET + PAGE_OFFSET) +#else + +#define __virt_to_bus(x) (x) +#define __bus_to_virt(x) (x) + +#endif /* CONFIG_MMU */ + #endif diff --git a/include/asm-arm/arch-ixp4xx/fast_timer.h b/include/asm-arm/arch-ixp4xx/fast_timer.h new file mode 100644 index 00000000..d3262f63 --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/fast_timer.h @@ -0,0 +1,53 @@ +#ifndef __ASM_ARM_MACH_FAST_TIMER_H +#define __ASM_ARM_MACH_FAST_TIMER_H + +#include +#include +#include +#include +#include + +static irqreturn_t +fast_timer_interrupt(int irq, void *dev_id) +{ + /* Clear Pending Interrupt by writing '1' to it */ + *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; + + do_fast_timer(); + return IRQ_HANDLED; +} + +static void fast_timer_set(void) +{ + unsigned long interval; + + /* Setup the Timer counter value */ + interval = (CLOCK_TICK_RATE + fast_timer_rate/2) / fast_timer_rate; + *IXP4XX_OSRT2 = (interval & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; +} + +static int __init fast_timer_setup(void) +{ + /* Clear Pending Interrupt by writing '1' to it */ + *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; + + /* Connect the interrupt handler and enable the interrupt */ + if (request_irq(IRQ_IXP4XX_TIMER2, fast_timer_interrupt, SA_INTERRUPT, + "fast timer", NULL)) + return -EBUSY; + + fast_timer_rate = 5000; + fast_timer_set(); + + printk("fast timer: %d Hz, IRQ %d\n", fast_timer_rate, + IRQ_IXP4XX_TIMER2); + return 0; +} + +static void __exit fast_timer_cleanup(void) +{ + *IXP4XX_OSRT2 = IXP4XX_OST_DISABLED; + free_irq(IRQ_IXP4XX_TIMER2, NULL); +} + +#endif diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h index 6acb69c9..8ed9f101 100644 --- a/include/asm-arm/arch-ixp4xx/hardware.h +++ b/include/asm-arm/arch-ixp4xx/hardware.h @@ -46,5 +46,6 @@ extern unsigned int processor_id; #include "prpmc1100.h" #include "nslu2.h" #include "nas100d.h" +#include "sg.h" #endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-ixp4xx/ide.h b/include/asm-arm/arch-ixp4xx/ide.h new file mode 100644 index 00000000..c3117137 --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/ide.h @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-ixp4xx/ide.h + * + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * Based on original code Copyright (c) 1998 Russell King + */ + + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + unsigned long reg = (unsigned long) data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long) ctrl_port; + if (irq) + *irq = 0; +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ + /* There are no standard ports */ +} + + diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h index f24b763c..2b53bce9 100644 --- a/include/asm-arm/arch-ixp4xx/irqs.h +++ b/include/asm-arm/arch-ixp4xx/irqs.h @@ -94,6 +94,24 @@ #define IRQ_COYOTE_IDE IRQ_IXP4XX_GPIO5 /* + * SnapGear SG590, SG710(ESS710) and SG720 PCI IRQs + */ +#define IRQ_SG590_PCI_INTA IRQ_IXP4XX_GPIO8 + +#define IRQ_ESS710_PCI_INTA IRQ_IXP4XX_GPIO6 +#define IRQ_ESS710_PCI_INTB IRQ_IXP4XX_GPIO7 +#define IRQ_ESS710_PCI_INTC IRQ_IXP4XX_GPIO8 + +#define IRQ_SG720_PCI_INTA IRQ_IXP4XX_GPIO8 +#define IRQ_SG720_PCI_INTB IRQ_IXP4XX_GPIO9 + +/* + * Intel IXP425 Montejade demonstration platform + */ +#define IRQ_MONTEJADE_PCI_INTA IRQ_IXP4XX_GPIO6 +#define IRQ_MONTEJADE_PCI_INTB IRQ_IXP4XX_GPIO7 + +/* * NSLU2 board IRQs */ #define IRQ_NSLU2_PCI_INTA IRQ_IXP4XX_GPIO11 diff --git a/include/asm-arm/arch-ixp4xx/memory.h b/include/asm-arm/arch-ixp4xx/memory.h index af9667b5..7c44185e 100644 --- a/include/asm-arm/arch-ixp4xx/memory.h +++ b/include/asm-arm/arch-ixp4xx/memory.h @@ -16,10 +16,12 @@ #if !defined(__ASSEMBLY__) && defined(CONFIG_PCI) +#ifdef CONFIG_PCI void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes); #define arch_adjust_zones(node, size, holes) \ ixp4xx_adjust_zones(node, size, holes) +#endif #define ISA_DMA_THRESHOLD (SZ_64M - 1) diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index 8d10a918..d5f71f04 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -132,6 +132,11 @@ static inline void gpio_line_config(u8 line, u32 direction) *IXP4XX_GPIO_GPOER &= ~(1 << line); } +static inline void gpio_line_isr_clear(u8 line) +{ + *IXP4XX_GPIO_GPISR = (1 << line); +} + static inline void gpio_line_get(u8 line, int *value) { *value = (*IXP4XX_GPIO_GPINR >> line) & 0x1; diff --git a/include/asm-arm/arch-ixp4xx/sg.h b/include/asm-arm/arch-ixp4xx/sg.h new file mode 100644 index 00000000..ee4550f6 --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/sg.h @@ -0,0 +1,20 @@ +/* + * include/asm-arm/arch-ixp4xx/sg.h + * + * Secure Computing/SnapGear platform specific definitions + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H__ +#error "Do not include this directly, instead #include " +#endif + +#include + +/* + * ixp4xx_exp_bus_size is not available during uncompress, + * but it is always 16M for this platform. + */ +#define SG565_WATCHDOG_EXP_CS IXP4XX_EXP_CS7 +#define SG565_WATCHDOG_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + (7 * SZ_16M)) + diff --git a/include/asm-arm/arch-ixp4xx/timex.h b/include/asm-arm/arch-ixp4xx/timex.h index 3745e35c..c8123673 100644 --- a/include/asm-arm/arch-ixp4xx/timex.h +++ b/include/asm-arm/arch-ixp4xx/timex.h @@ -10,6 +10,10 @@ * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the * timer register ignores the bottom 2 bits of the LATCH value. */ +#if defined(CONFIG_IXP4XX_CLOCK_FORCE) +#define FREQ CONFIG_IXP4XX_CLOCK +#else #define FREQ 66666666 +#endif #define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ) diff --git a/include/asm-arm/arch-ixp4xx/uncompress.h b/include/asm-arm/arch-ixp4xx/uncompress.h index 09ae6c91..ba49a1f0 100644 --- a/include/asm-arm/arch-ixp4xx/uncompress.h +++ b/include/asm-arm/arch-ixp4xx/uncompress.h @@ -19,16 +19,19 @@ #define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE) +static int console_output = 1; static volatile u32* uart_base; static inline void putc(int c) { /* Check THRE and TEMT bits before we transmit the character. */ - while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) - barrier(); + if (console_output) { + while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) + barrier(); - *uart_base = c; + *uart_base = c; + } } static void flush(void) @@ -44,6 +47,11 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id) uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS; else uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS; + + if (machine_is_ess710() || machine_is_ivpn() || machine_is_sg560() || + machine_is_sg565() || machine_is_sg580() || machine_is_sg720() || + machine_is_shiva1100() || machine_is_sg590()) + console_output = 0; } /* @@ -51,6 +59,16 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id) */ #define arch_decomp_setup() __arch_decomp_setup(arch_id) +#if defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \ + defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_SG720) || \ + defined(CONFIG_MACH_SG590) || defined(CONFIG_MACH_IVPN) +#define arch_decomp_wdog() \ + *((volatile u32 *)(IXP4XX_GPIO_BASE_PHYS+IXP4XX_GPIO_GPOUTR_OFFSET)) ^= 0x00004000 +#elif defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SHIVA1100) +#define arch_decomp_wdog() \ + *((volatile unsigned char *) SG565_WATCHDOG_BASE_PHYS) = 0 +#else #define arch_decomp_wdog() +#endif #endif diff --git a/include/asm-arm/arch-ks8695/debug-macro.S b/include/asm-arm/arch-ks8695/debug-macro.S new file mode 100644 index 00000000..0b341c20 --- /dev/null +++ b/include/asm-arm/arch-ks8695/debug-macro.S @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-ks8695/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * (C) Copyright 2006 Greg Ungerer + * + * 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. + */ + +.macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x03000000 @ 0x03ffe000 + orreq \rx, \rx, #0x00ff0000 + movne \rx, #0xff000000 @ 0xff00e000 + orr \rx, \rx, #0x0000e000 +.endm + +.macro senduart,rd,rx + str \rd, [\rx, #0x4] +.endm + +.macro waituart,rd,rx +1: ldr \rd, [\rx, #0x14] + and \rd, \rd, #0x40 @ check TEMT bit + teq \rd, #0x40 + bne 1b +.endm + +.macro busyuart,rd,rx +.endm + diff --git a/include/asm-arm/arch-ks8695/dma.h b/include/asm-arm/arch-ks8695/dma.h new file mode 100644 index 00000000..d1a28a66 --- /dev/null +++ b/include/asm-arm/arch-ks8695/dma.h @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-ks8695/dma.h + * + * Copyright (C) 1997,1998 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. + * + * 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 + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_CHANNELS 0 +#define MAX_DMA_ADDRESS 0xffffffff + +#endif /* __ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-ks8695/entry-macro.S b/include/asm-arm/arch-ks8695/entry-macro.S new file mode 100644 index 00000000..f2ad0a93 --- /dev/null +++ b/include/asm-arm/arch-ks8695/entry-macro.S @@ -0,0 +1,28 @@ +/* + * include/asm-arm/arch-ks8695/entry-macro.S + * + * Low-level IRQ helper macros for KS8695 based platforms + * + * 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. + */ + +.macro disable_fiq +.endm + + +.macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqnr, =KS8695_IO_VIRT+KS8695_INT_MASK_STATUS + ldr \irqstat, [\irqnr] @ get masked status + + mov \irqnr, #0 +1001: tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #32 + bcc 1001b +1002: @ EQ will be set if we reach +.endm + diff --git a/include/asm-arm/arch-ks8695/fast_timer.h b/include/asm-arm/arch-ks8695/fast_timer.h new file mode 100644 index 00000000..5527205e --- /dev/null +++ b/include/asm-arm/arch-ks8695/fast_timer.h @@ -0,0 +1,56 @@ +#ifndef __ASM_ARM_MACH_FAST_TIMER_H +#define __ASM_ARM_MACH_FAST_TIMER_H + +#include +#include +#include +#include +#include +#include + +static irqreturn_t fast_timer_interrupt(int irq, void *dev_id) +{ + __raw_writel(KS8695_INTMASK_TIMERINT0, KS8695_REG(KS8695_INT_STATUS)); + do_fast_timer(); + return IRQ_HANDLED; +} + +static void fast_timer_set(void) +{ + unsigned long interval, data, pulse, ctrl; + + /* Setup TIMER0 as fast clock */ + interval = (CLOCK_TICK_RATE/1000000) * fast_timer_rate; + data = interval >> 1; + pulse = interval - data; + __raw_writel(data, KS8695_REG(KS8695_TIMER0)); + __raw_writel(pulse, KS8695_REG(KS8695_TIMER0_PCOUNT)); + ctrl = __raw_readl(KS8695_REG(KS8695_TIMER_CTRL)) | 0x01; + __raw_writel(ctrl, KS8695_REG(KS8695_TIMER_CTRL)); +} + +static int __init fast_timer_setup(void) +{ + /* Connect the interrupt handler and enable the interrupt */ + if (request_irq(KS8695_INT_TIMERINT0, fast_timer_interrupt, + SA_INTERRUPT, "fast timer", NULL)) + return -EBUSY; + + fast_timer_rate = 2000; + fast_timer_set(); + + printk("fast timer: %d Hz, IRQ %d\n", fast_timer_rate, + KS8695_INT_TIMERINT0); + return 0; +} + +static void __exit fast_timer_cleanup(void) +{ + unsigned long ctrl; + + ctrl = __raw_readl(KS8695_REG(KS8695_TIMER_CTRL)) & 0x02; + __raw_writel(ctrl, KS8695_REG(KS8695_TIMER_CTRL)); + free_irq(KS8695_INT_TIMERINT0, NULL); +} + +#endif diff --git a/include/asm-arm/arch-ks8695/hardware.h b/include/asm-arm/arch-ks8695/hardware.h new file mode 100644 index 00000000..1ec7c38c --- /dev/null +++ b/include/asm-arm/arch-ks8695/hardware.h @@ -0,0 +1,38 @@ +/* + * linux/include/asm-arm/arch-ks8695/hardware.h + * + * This file contains the hardware definitions of the KS8695. + * + * Copyright (C) 2002 Micrel 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. + * + * 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 + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +/* + * Virtual memory mapping of the KS8695 internal register area. + * This is a static mapping, set up early in kernel startup. + */ +#define KS8695_IO_VIRT 0xFF000000 +#define KS8695_REG(x) ((void __iomem *)(KS8695_IO_VIRT + (x))) + +#define pcibios_assign_all_busses() 1 +#define PCIBIOS_MIN_IO 0x00000100 +#define PCIBIOS_MIN_MEM 0x00010000 +#define PCI_MEMORY_VADDR KS8695P_PCIBG_MEM_BASE +#define PCI_IO_VADDR KS8695P_PCIBG_IO_BASE + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-ks8695/io.h b/include/asm-arm/arch-ks8695/io.h new file mode 100644 index 00000000..11b63a5d --- /dev/null +++ b/include/asm-arm/arch-ks8695/io.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/arch-ks8695/io.h + * + * Copyright (C) 1999 ARM Limited + * + * 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 + */ +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#include + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#endif /* __ASM_ARCH_IO_H */ diff --git a/include/asm-arm/arch-ks8695/irqs.h b/include/asm-arm/arch-ks8695/irqs.h new file mode 100644 index 00000000..a5ae15d3 --- /dev/null +++ b/include/asm-arm/arch-ks8695/irqs.h @@ -0,0 +1,98 @@ +/* + * linux/include/asm-arm/arch-ks8695/irqs.h + * + * Copyright (C) 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 + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H 1 + +/* + * IRQ definitions + */ +#define KS8695_INT_EXT_INT0 2 +#define KS8695_INT_EXT_INT1 3 +#define KS8695_INT_EXT_INT2 4 +#define KS8695_INT_EXT_INT3 5 +#define KS8695_INT_TIMERINT0 6 +#define KS8695_INT_TIMERINT1 7 +#define KS8695_INT_UART_TX 8 +#define KS8695_INT_UART_RX 9 +#define KS8695_INT_UART_LINE_ERR 10 +#define KS8695_INT_UART_MODEMS 11 +#define KS8695_INT_LAN_STOP_RX 12 +#define KS8695_INT_LAN_STOP_TX 13 +#define KS8695_INT_LAN_BUF_RX_STATUS 14 +#define KS8695_INT_LAN_BUF_TX_STATUS 15 +#define KS8695_INT_LAN_RX_STATUS 16 +#define KS8695_INT_LAN_TX_STATUS 17 +#define KS8695_INT_HPAN_STOP_RX 18 +#define KS8695_INT_HPNA_STOP_TX 19 +#define KS8695_INT_HPNA_BUF_RX_STATUS 20 +#define KS8695_INT_HPNA_BUF_TX_STATUS 21 +#define KS8695_INT_HPNA_RX_STATUS 22 +#define KS8695_INT_HPNA_TX_STATUS 23 +#define KS8695_INT_BUS_ERROR 24 +#define KS8695_INT_WAN_STOP_RX 25 +#define KS8695_INT_WAN_STOP_TX 26 +#define KS8695_INT_WAN_BUF_RX_STATUS 27 +#define KS8695_INT_WAN_BUF_TX_STATUS 28 +#define KS8695_INT_WAN_RX_STATUS 29 +#define KS8695_INT_WAN_TX_STATUS 30 + +#define KS8695_INT_UART KS8695_INT_UART_TX + +/* + * IRQ bit masks + */ +#define KS8695_INTMASK_EXT_INT0 (1 << KS8695_INT_EXT_INT0) +#define KS8695_INTMASK_EXT_INT1 (1 << KS8695_INT_EXT_INT1) +#define KS8695_INTMASK_EXT_INT2 (1 << KS8695_INT_EXT_INT2) +#define KS8695_INTMASK_EXT_INT3 (1 << KS8695_INT_EXT_INT3) +#define KS8695_INTMASK_TIMERINT0 (1 << KS8695_INT_TIMERINT0) +#define KS8695_INTMASK_TIMERINT1 (1 << KS8695_INT_TIMERINT1) +#define KS8695_INTMASK_UART_TX (1 << KS8695_INT_UART_TX) +#define KS8695_INTMASK_UART_RX (1 << KS8695_INT_UART_RX) +#define KS8695_INTMASK_UART_LINE_ERR (1 << KS8695_INT_UART_LINE_ERR) +#define KS8695_INTMASK_UART_MODEMS (1 << KS8695_INT_UART_MODEMS) +#define KS8695_INTMASK_LAN_STOP_RX (1 << KS8695_INT_LAN_STOP_RX) +#define KS8695_INTMASK_LAN_STOP_TX (1 << KS8695_INT_LAN_STOP_TX) +#define KS8695_INTMASK_LAN_BUF_RX_STATUS (1 << KS8695_INT_LAN_BUF_RX_STATUS) +#define KS8695_INTMASK_LAN_BUF_TX_STATUS (1 << KS8695_INT_LAN_BUF_TX_STATUS) +#define KS8695_INTMASK_LAN_RX_STATUS (1 << KS8695_INT_LAN_RX_STATUS) +#define KS8695_INTMASK_LAN_TX_STATUS (1 << KS8695_INT_LAN_RX_STATUS) +#define KS8695_INTMASK_HPAN_STOP_RX (1 << KS8695_INT_HPAN_STOP_RX) +#define KS8695_INTMASK_HPNA_STOP_TX (1 << KS8695_INT_HPNA_STOP_TX) +#define KS8695_INTMASK_HPNA_BUF_RX_STATUS (1 << KS8695_INT_HPNA_BUF_RX_STATUS) +#define KS8695_INTMAKS_HPNA_BUF_TX_STATUS (1 << KS8695_INT_HPNA_BUF_TX_STATUS) +#define KS8695_INTMASK_HPNA_RX_STATUS (1 << KS8695_INT_HPNA_RX_STATUS) +#define KS8695_INTMASK_HPNA_TX_STATUS (1 << KS8695_INT_HPNA_TX_STATUS) +#define KS8695_INTMASK_BUS_ERROR (1 << KS8695_INT_BUS_ERROR) +#define KS8695_INTMASK_WAN_STOP_RX (1 << KS8695_INT_WAN_STOP_RX) +#define KS8695_INTMASK_WAN_STOP_TX (1 << KS8695_INT_WAN_STOP_TX) +#define KS8695_INTMASK_WAN_BUF_RX_STATUS (1 << KS8695_INT_WAN_BUF_RX_STATUS) +#define KS8695_INTMASK_WAN_BUF_TX_STATUS (1 << KS8695_INT_WAN_BUF_TX_STATUS) +#define KS8695_INTMASK_WAN_RX_STATUS (1 << KS8695_INT_WAN_RX_STATUS) +#define KS8695_INTMASK_WAN_TX_STATUS (1 << KS8695_INT_WAN_TX_STATUS) + +#define KS8695_SC_VALID_INT 0xFFFFFFFF + + +#define NR_IRQS (32) + +#endif /* __ASM_ARCH_IRQS_H */ diff --git a/include/asm-arm/arch-ks8695/ks8695-pci.h b/include/asm-arm/arch-ks8695/ks8695-pci.h new file mode 100644 index 00000000..79cd6845 --- /dev/null +++ b/include/asm-arm/arch-ks8695/ks8695-pci.h @@ -0,0 +1,68 @@ +/* + * 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 + */ +#ifndef __ASM_ARCH_PLATFORM_PCI_H +#define __ASM_ARCH_PLATFORM_PCI_H 1 + +/* PCI memory related defines */ +#define KS8695P_PCIBG_MEM_BASE 0x60000000 /* memory base for bridge*/ +#define KS8695P_PCI_MEM_BASE 0x60000000UL/* memory base in PCI space */ +#define KS8695P_PCI_MEM_SIZE 0x20000000UL/* 512M, can be extended */ +#define KS8695P_PCI_MEM_MASK 0xE0000000 /* 512M */ + +/* PCI IO related defines */ +#define KS8695P_PCIBG_IO_BASE 0x10000000 /* io base for bridge */ +#define KS8695P_PCI_IO_BASE 0x10000000 +#define KS8695P_PCI_IO_SIZE 0x00010000 /* 64K */ +#define KS8695P_PCI_IO_MASK 0xFF800000 /* 64K range */ + +/* new registers specific to KS8695P */ +/* PCI related */ +#define KS8695_CRCFID 0x2000 +#define KS8695_CRCFCS 0x2004 +#define KS8695_CRCFRV 0x2008 +#define KS8695_CRCFLT 0x200c +#define KS8695_CRCBMA 0x2010 +#define KS8695_CRCBA0 0x2014 +#define KS8695_CRCSID 0x202c +#define KS8695_CRCFIT 0x203c + +/* bridge configuration related registers */ +#define KS8695_PBCA 0x2100 +#define KS8695_PBCD 0x2104 + +/* bridge mode related registers */ +#define KS8695_PBM 0x2200 +#define KS8695_PBCS 0x2204 +#define KS8695_PMBA 0x2208 +#define KS8695_PMBAC 0x220c +#define KS8695_PMBAM 0x2210 +#define KS8695_PMBAT 0x2214 +#define KS8695_PIOBA 0x2218 +#define KS8695_PIOBAC 0x221c +#define KS8695_PIOBAM 0x2220 +#define KS8695_PIOBAT 0x2224 + +/* bits for registers */ +/* 0x2200 */ +#define PBM_BRIDGE_MODE 0x80000000 + +/* 0x2204 */ +#define PBCS_SW_RESET 0x80000000 + +/* 0x220c */ +#define PMBAC_TRANS_ENABLE 0x80000000 + +#endif /* __ASM_ARCH_PLATFORM_PCI_H */ diff --git a/include/asm-arm/arch-ks8695/ks8695-regs.h b/include/asm-arm/arch-ks8695/ks8695-regs.h new file mode 100644 index 00000000..a6343087 --- /dev/null +++ b/include/asm-arm/arch-ks8695/ks8695-regs.h @@ -0,0 +1,341 @@ +/* + * 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 + */ +#ifndef __ASM_ARCH_KS8695_REGS_H +#define __ASM_ARCH_KS8695_REGS_H 1 + +/* Physical IO address space of KS8695 internal peripheral registers */ +#define KS8695_IO_BASE 0x03FF0000 +#define KS8695_IO_SIZE 0x00010000 + +#define KS8695_SYSTEN_CONFIG 0x00 +#define KS8695_SYSTEN_BUS_CLOCK 0x04 + +/* bus clock definitions*/ +#define KS8695_BUS_CLOCK_125MHZ 0x0 +#define KS8695_BUS_CLOCK_100MHZ 0x1 +#define KS8695_BUS_CLOCK_62MHZ 0x2 +#define KS8695_BUS_CLOCK_50MHZ 0x3 +#define KS8695_BUS_CLOCK_41MHZ 0x4 +#define KS8695_BUS_CLOCK_33MHZ 0x5 +#define KS8695_BUS_CLOCK_31MHZ 0x6 +#define KS8695_BUS_CLOCK_25MHZ 0x7 + +/* i/o control registers offset difinitions */ +#define KS8695_IO_CTRL0 0x4000 +#define KS8695_IO_CTRL1 0x4004 +#define KS8695_IO_CTRL2 0x4008 +#define KS8695_IO_CTRL3 0x400C + +/* memory control registers offset difinitions */ +#define KS8695_MEM_CTRL0 0x4010 +#define KS8695_MEM_CTRL1 0x4014 +#define KS8695_MEM_CTRL2 0x4018 +#define KS8695_MEM_CTRL3 0x401C +#define KS8695_MEM_GENERAL 0x4020 +#define KS8695_SDRAM_CTRL0 0x4030 +#define KS8695_SDRAM_CTRL1 0x4034 +#define KS8695_SDRAM_GENERAL 0x4038 +#define KS8695_SDRAM_BUFFER 0x403C +#define KS8695_SDRAM_REFRESH 0x4040 + +/* WAN control registers offset difinitions */ +#define KS8695_WAN_DMA_TX 0x6000 +#define KS8695_WAN_DMA_RX 0x6004 +#define KS8695_WAN_DMA_TX_START 0x6008 +#define KS8695_WAN_DMA_RX_START 0x600C +#define KS8695_WAN_TX_LIST 0x6010 +#define KS8695_WAN_RX_LIST 0x6014 +#define KS8695_WAN_MAC_LOW 0x6018 +#define KS8695_WAN_MAC_HIGH 0x601C +#define KS8695_WAN_MAC_ELOW 0x6080 +#define KS8695_WAN_MAC_EHIGH 0x6084 + +/* LAN control registers offset difinitions */ +#define KS8695_LAN_DMA_TX 0x8000 +#define KS8695_LAN_DMA_RX 0x8004 +#define KS8695_LAN_DMA_TX_START 0x8008 +#define KS8695_LAN_DMA_RX_START 0x800C +#define KS8695_LAN_TX_LIST 0x8010 +#define KS8695_LAN_RX_LIST 0x8014 +#define KS8695_LAN_MAC_LOW 0x8018 +#define KS8695_LAN_MAC_HIGH 0x801C +#define KS8695_LAN_MAC_ELOW 0X8080 +#define KS8695_LAN_MAC_EHIGH 0X8084 + +/* HPNA control registers offset difinitions */ +#define KS8695_HPNA_DMA_TX 0xA000 +#define KS8695_HPNA_DMA_RX 0xA004 +#define KS8695_HPNA_DMA_TX_START 0xA008 +#define KS8695_HPNA_DMA_RX_START 0xA00C +#define KS8695_HPNA_TX_LIST 0xA010 +#define KS8695_HPNA_RX_LIST 0xA014 +#define KS8695_HPNA_MAC_LOW 0xA018 +#define KS8695_HPNA_MAC_HIGH 0xA01C +#define KS8695_HPNA_MAC_ELOW 0xA080 +#define KS8695_HPNA_MAC_EHIGH 0xA084 + +/* UART control registers offset difinitions */ +#define KS8695_UART_RX_BUFFER 0xE000 +#define KS8695_UART_TX_HOLDING 0xE004 + +#define KS8695_UART_FIFO_CTRL 0xE008 +#define KS8695_UART_FIFO_TRIG01 0x00 +#define KS8695_UART_FIFO_TRIG04 0x80 +#define KS8695_UART_FIFO_TXRST 0x03 +#define KS8695_UART_FIFO_RXRST 0x02 +#define KS8695_UART_FIFO_FEN 0x01 + +#define KS8695_UART_LINE_CTRL 0xE00C +#define KS8695_UART_LINEC_BRK 0x40 +#define KS8695_UART_LINEC_EPS 0x10 +#define KS8695_UART_LINEC_PEN 0x08 +#define KS8695_UART_LINEC_STP2 0x04 +#define KS8695_UART_LINEC_WLEN8 0x03 +#define KS8695_UART_LINEC_WLEN7 0x02 +#define KS8695_UART_LINEC_WLEN6 0x01 +#define KS8695_UART_LINEC_WLEN5 0x00 + +#define KS8695_UART_MODEM_CTRL 0xE010 +#define KS8695_UART_MODEMC_RTS 0x02 +#define KS8695_UART_MODEMC_DTR 0x01 + +#define KS8695_UART_LINE_STATUS 0xE014 +#define KS8695_UART_LINES_TXFE 0x20 +#define KS8695_UART_LINES_BE 0x10 +#define KS8695_UART_LINES_FE 0x08 +#define KS8695_UART_LINES_PE 0x04 +#define KS8695_UART_LINES_OE 0x02 +#define KS8695_UART_LINES_RXFE 0x01 +#define KS8695_UART_LINES_ANY (KS8695_UART_LINES_OE | \ + KS8695_UART_LINES_BE | \ + KS8695_UART_LINES_PE | \ + KS8695_UART_LINES_FE) + +#define KS8695_UART_MODEM_STATUS 0xE018 +#define KS8695_UART_MODEM_DCD 0x80 +#define KS8695_UART_MODEM_DSR 0x20 +#define KS8695_UART_MODEM_CTS 0x10 +#define KS8695_UART_MODEM_DDCD 0x08 +#define KS8695_UART_MODEM_DDSR 0x02 +#define KS8695_UART_MODEM_DCTS 0x01 +#define KS8695_UART_MODEM_ANY 0xFF + +#define KS8695_UART_DIVISOR 0xE01C +#define KS8695_UART_STATUS 0xE020 + +/* Interrupt controlller registers offset difinitions */ +#define KS8695_INT_CONTL 0xE200 +#define KS8695_INT_ENABLE 0xE204 +#define KS8695_INT_ENABLE_MODEM 0x0800 +#define KS8695_INT_ENABLE_ERR 0x0400 +#define KS8695_INT_ENABLE_RX 0x0200 +#define KS8695_INT_ENABLE_TX 0x0100 +#define KS8695_INT_UART_MASK 0x0f00 + +#define KS8695_INT_STATUS 0xE208 +#define KS8695_INT_WAN_PRIORITY 0xE20C +#define KS8695_INT_HPNA_PRIORITY 0xE210 +#define KS8695_INT_LAN_PRIORITY 0xE214 +#define KS8695_INT_TIMER_PRIORITY 0xE218 +#define KS8695_INT_UART_PRIORITY 0xE21C +#define KS8695_INT_EXT_PRIORITY 0xE220 +#define KS8695_INT_CHAN_PRIORITY 0xE224 +#define KS8695_INT_BUSERROR_PRO 0xE228 +#define KS8695_INT_MASK_STATUS 0xE22C +#define KS8695_FIQ_PEND_PRIORITY 0xE230 +#define KS8695_IRQ_PEND_PRIORITY 0xE234 + +/* timer registers offset difinitions */ +#define KS8695_TIMER_CTRL 0xE400 +#define KS8695_TIMER1 0xE404 +#define KS8695_TIMER0 0xE408 +#define KS8695_TIMER1_PCOUNT 0xE40C +#define KS8695_TIMER0_PCOUNT 0xE410 + +/* GPIO registers offset difinitions */ +#define KS8695_GPIO_MODE 0xE600 +#define KS8695_GPIO_CTRL 0xE604 +#define KS8695_GPIO_DATA 0xE608 + +/* SWITCH registers offset difinitions */ +#define KS8695_SWITCH_CTRL0 0xE800 +#define KS8695_SWITCH_CTRL1 0xE804 +#define KS8695_SWITCH_PORT1 0xE808 +#define KS8695_SWITCH_PORT2 0xE80C +#define KS8695_SWITCH_PORT3 0xE810 +#define KS8695_SWITCH_PORT4 0xE814 +#define KS8695_SWITCH_PORT5 0xE818 +#define KS8695_SWITCH_LUE_CTRL 0xE824 +#define KS8695_SWITCH_LUE_HIGH 0xE828 +#define KS8695_SWITCH_LUE_LOW 0xE82C + +/* some differences between the KS8695(X) and KS8695P */ +#ifdef CONFIG_PCI +#define KS8695_SWITCH_AUTO0 0xE848 +#define KS8695_SWITCH_AUTO1 0xE84C +#define KS8695_SWITCH_ADVANCED 0xE860 +#define KS8695_DSCP_HIGH 0xE864 +#define KS8695_DSCP_LOW 0xE868 +#define KS8695_SWITCH_MAC_HIGH 0xE86C +#define KS8695_SWITCH_MAC_LOW 0xE870 +#define KS8695_LAN12_POWERMAGR 0xE874 +#define KS8695_LAN34_POWERMAGR 0xE878 +#else +#define KS8695_SWITCH_AUTO0 0xE81C +#define KS8695_SWITCH_AUTO1 0xE820 +#define KS8695_SWITCH_ADVANCED 0xE830 +#define KS8695_DSCP_HIGH 0xE834 +#define KS8695_DSCP_LOW 0xE838 +#define KS8695_SWITCH_MAC_HIGH 0xE83C +#define KS8695_SWITCH_MAC_LOW 0xE840 +#define KS8695_LAN12_POWERMAGR 0xE84C +#define KS8695_LAN34_POWERMAGR 0xE850 +#endif + +/* miscellaneours registers difinitions */ +#define KS8695_MANAGE_COUNTER 0xE844 +#define KS8695_MANAGE_DATA 0xE848 + +#define KS8695_DEVICE_ID 0xEA00 +#define KS8695_REVISION_ID 0xEA04 + +#define KS8695_MISC_CONTROL 0xEA08 +#define KS8695_WAN_CONTROL 0xEA0C +#define KS8695_WAN_POWERMAGR 0xEA10 +#define KS8695_WAN_PHY_CONTROL 0xEA14 +#define KS8695_WAN_PHY_STATUS 0xEA18 + + +/* + * The following are all new in the KS8695P. + */ +#ifdef CONFIG_PCI + +/* most bit definition are same as KS8695, except few new bits */ +#define KS8695_SEC0 0xE800 +#define KS8695_SEC1 0xE804 + +/* new bits */ +#define KS8695_SEC0_BACKOFF_EN 0x80000000 +#define KS8695_SEC0_FRAME_LEN_CHECK 0x00020000 +#define KS8695_SEC0_DMA_HALF_DUPLEX 0x00000010 + +/* new bits */ +#define KS8695_SEC1_NO_IEEE_AN 0x00000800 +#define KS8695_SEC1_TPID_MODE 0x00000400 +#define KS8695_SEC1_NO_TX_8021X_FLOW_CTRL 0x00000080 +#define KS8695_SEC1_NO_RX_8021X_FLOW_CTRL 0x00000040 +#define KS8695_SEC1_HUGE_PACKET 0x00000020 +#define KS8695_SEC1_8021Q_VLAN_EN 0x00000010 +#define KS8695_SEC1_MII_10BT 0x00000002 +#define KS8695_SEC1_NULL_VID 0x00000001 + +/* Port 1-4 and 5 Configuration Register Set 1 */ +#define KS8695_SEP1C1 0xE80C +#define KS8695_SEP2C1 0xE818 +#define KS8695_SEP3C1 0xE824 +#define KS8695_SEP4C1 0xE830 +#define KS8695_SEP5C1 0xE83C + +/* Port 1-4 and 5 Configuration Register Set 2 */ +#define KS8695_SEP1C2 0xE810 +#define KS8695_SEP2C2 0xE81C +#define KS8695_SEP3C2 0xE828 +#define KS8695_SEP4C2 0xE834 +#define KS8695_SEP5C2 0xE840 + +#define KS8695_SEPC2_VLAN_FILTER 0x10000000 +#define KS8695_SEPC2_DISCARD_NON_PVID 0x08000000 +#define KS8695_SEPC2_FORCE_FLOW_CTRL 0x04000000 +#define KS8695_SEPC2_BACK_PRESSURE_EN 0x02000000 + +#define KS8695_SEPC2_TX_H_RATECTRL_MASK 0x00FFF000 +#define KS8695_SEPC2_TX_L_RATECTRL_MASK 0x00000FFF + +/* Port 1-4 and 5 Configuration Register Set 3 */ +#define KS8695_SEP1C3 0xE814 +#define KS8695_SEP2C3 0xE820 +#define KS8695_SEP3C3 0xE82C +#define KS8695_SEP4C3 0xE838 +#define KS8695_SEP5C3 0xE844 + +#define KS8695_SEPC3_RX_H_RATECTRL_MASK 0xFFF00000 +#define KS8695_SEPC3_RX_L_RATECTRL_MASK 0x000FFF00 +#define KS8695_SEPC3_RX_DIF_RATECTRL_EN 0x00000080 +#define KS8695_SEPC3_RX_L_RATECTRL_EN 0x00000040 +#define KS8695_SEPC3_RX_H_RATECTRL_EN 0x00000020 +#define KS8695_SEPC3_RX_L_RATEFLOW_EN 0x00000010 +#define KS8695_SEPC3_RX_H_RATEFLOW_EN 0x00000008 +#define KS8695_SEPC3_TX_DIF_RATECTRL_EN 0x00000004 +#define KS8695_SEPC3_TX_L_RATECTRL_EN 0x00000002 +#define KS8695_SEPC3_TX_H_RATECTRL_EN 0x00000001 + +/* Port auto negotiation related registers */ +#define KS8695_SEP12AN 0xE848 +#define KS8695_SEP34AN 0xE84C + +/* Indirect Access Control register */ +#define KS8695_SEIAC 0xE850 +#define KS8695_SEIADH2 0xE854 +#define KS8695_SEIADH1 0xE858 +#define KS8695_SEIADL 0xE85C + +#define KS8695_SEIAC_READ 0x00001000 +#define KS8695_SEIAC_WRITE 0x00000000 +#define KS8695_SEIAC_TAB_STATIC 0x00000000 +#define KS8695_SEIAC_TAB_VLAN 0x00000400 +#define KS8695_SEIAC_TAB_DYNAMIC 0x00000800 +#define KS8695_SEIAC_TAB_MIB 0x00000C00 +#define KS8695_SEIAC_INDEX_MASK 0x000003FF + +/* Advanced Feature Control register */ +#define KS8695_SEAFC 0xE860 +#define KS8695_SEDSCPH 0xE864 +#define KS8695_SEDSCPL 0xE868 +#define KS8695_SEMAH 0xE86C +#define KS8695_SEMAL 0xE870 + +/* LAN PHY power management related registers */ +#define KS8695_LPPM12 0xE874 +#define KS8695_LPPM34 0xE878 + +/* new bits */ +#define KS8695_LPPM_PHY_LOOPBACK 0x4000 +#define KS8695_LPPM_RMT_LOOPBACK 0x2000 +#define KS8695_LPPM_PHY_ISOLATE 0x1000 +#define KS8695_LPPM_SOFT_RESET 0x0800 +#define KS8695_LPPM_FORCE_LINK 0x0400 + +/* new bits */ +#define KS8695_LPPM_PHY_LOOPBACK 0x4000 +#define KS8695_LPPM_RMT_LOOPBACK 0x2000 +#define KS8695_LPPM_PHY_ISOLATE 0x1000 +#define KS8695_LPPM_SOFT_RESET 0x0800 +#define KS8695_LPPM_FORCE_LINK 0x0400 + +/* Digital Testing Status and Control Registers */ +#define KS8695_SEDTS 0xE87C +#define KS8695_SEATCS 0xE880 + +/* new bits for WAN PHY Power mangement register */ +#define KS8695_WPPM_PHY_LOOPBACK 0x00004000 +#define KS8695_WPPM_RMT_LOOPBACK 0x00002000 +#define KS8695_WPPM_PHY_ISOLATION 0x00001000 +#define KS8695_WPPM_FORCE_LINK 0x00000400 + +#endif /* CONFIG_PCI */ + +#endif /* __ASM_ARCH_KS8695_REGS_H */ diff --git a/include/asm-arm/arch-ks8695/memory.h b/include/asm-arm/arch-ks8695/memory.h new file mode 100644 index 00000000..69f8954f --- /dev/null +++ b/include/asm-arm/arch-ks8695/memory.h @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/arch-ks8695/memory.h + * + * Copyright (C) 2002 Micrel 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. + * + * 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 + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#include +#include +#include + +/* + * All the current machines based on this I know of have RAM based at + * address 0. Lets deal with any that don't if/when we hit them. + */ +#define PHYS_OFFSET UL(0x00000000) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + * On KS8695, physical and bus address are same for dram + */ +#define __virt_to_bus(x) ((x) - PAGE_OFFSET + KS8695P_PCI_MEM_BASE) +#define __bus_to_virt(x) ((x) - KS8695P_PCI_MEM_BASE + PAGE_OFFSET) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-ks8695/param.h b/include/asm-arm/arch-ks8695/param.h new file mode 100644 index 00000000..2b716f3b --- /dev/null +++ b/include/asm-arm/arch-ks8695/param.h @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-ks8695/param.h + * + * Copyright (C) 1999 ARM Limited + * + * 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 + */ + diff --git a/include/asm-arm/arch-ks8695/system.h b/include/asm-arm/arch-ks8695/system.h new file mode 100644 index 00000000..ede50a34 --- /dev/null +++ b/include/asm-arm/arch-ks8695/system.h @@ -0,0 +1,48 @@ +/* + * linux/include/asm-arm/arch-ks8695/system.h + * + * Copyright (C) 2002 Micrel 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. + * + * 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 + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + +static void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + unsigned int val; + + /* To reset, use the watchdog timer */ + val = __raw_readl(KS8695_REG(KS8695_TIMER_CTRL)) & 0x02; + __raw_writel(val, KS8695_REG(KS8695_TIMER_CTRL)); + val = (10 << 8) | 0xFF; + __raw_writel(val, KS8695_REG(KS8695_TIMER0)); + val = __raw_readl(KS8695_REG(KS8695_TIMER_CTRL)) | 0x01; + __raw_writel(val, KS8695_REG(KS8695_TIMER_CTRL)); +} + +#endif /* __ASM_ARCH_SYSTEM_H */ diff --git a/include/asm-arm/arch-ks8695/timex.h b/include/asm-arm/arch-ks8695/timex.h new file mode 100644 index 00000000..260b25d2 --- /dev/null +++ b/include/asm-arm/arch-ks8695/timex.h @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-ks8695/timex.h + * + * Copyright (C) 1999 ARM Limited + * + * 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 + */ + +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H 1 + +#define CLOCK_TICK_RATE (25000000) + +#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/include/asm-arm/arch-ks8695/uncompress.h b/include/asm-arm/arch-ks8695/uncompress.h new file mode 100644 index 00000000..aec077c0 --- /dev/null +++ b/include/asm-arm/arch-ks8695/uncompress.h @@ -0,0 +1,53 @@ +/* + * linux/include/asm-arm/arch-ks8695/uncompress.h + * + * Copyright (C) 1999 ARM Limited + * + * 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 + +/* + * These access routines operate on the physical address space. + */ +static inline unsigned int ks8695_getreg(unsigned int r) +{ + return *((unsigned int *) (KS8695_IO_BASE + r)); +} + +static inline void ks8695_setreg(unsigned int r, unsigned int v) +{ + *((unsigned int *) (KS8695_IO_BASE + r)) = v; +} + +static void putc(char c) +{ + while ((ks8695_getreg(KS8695_UART_LINE_STATUS) & KS8695_UART_LINES_TXFE) == 0) + ; + + ks8695_setreg(KS8695_UART_TX_HOLDING, c); +} + +static void flush(void) +{ +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-ks8695/vmalloc.h b/include/asm-arm/arch-ks8695/vmalloc.h new file mode 100644 index 00000000..ed2a43dc --- /dev/null +++ b/include/asm-arm/arch-ks8695/vmalloc.h @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-ks8695/vmalloc.h + * + * Copyright (C) 2000 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. + * + * 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 + */ + +#ifndef __ASM_ARCH_VMALLOC_H +#define __ASM_ARCH_VMALLOC_H 1 + +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) + +#endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/include/asm-arm/arch-lpc22xx/dma.h b/include/asm-arm/arch-lpc22xx/dma.h new file mode 100644 index 00000000..b541edef --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/dma.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-armnommu/arch-lpc22xx/dma.h + * + * Copyright (C) 2004 Philips Semiconductors + */ + +#include +#include + +#ifndef __ASM_LPC22xx_ARCH_DMA_H +#define __ASM_LPC22xx_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x03000000 /* used in alloc_bootmem,see linux/bootmem.h*/ + +/* + * The LPC22xx has no DMA channels. + */ +#undef MAX_DMA_CHANNELS /* lpc22xx has no dma */ + +#endif /* _ASM_LPC22xx_ARCH_DMA_H */ + diff --git a/include/asm-arm/arch-lpc22xx/entry-macro.S b/include/asm-arm/arch-lpc22xx/entry-macro.S new file mode 100644 index 00000000..b2ecad37 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/entry-macro.S @@ -0,0 +1,34 @@ +/* + * include/arm/arch-lpc22xx/entry-macro.S + * + * Copyright (C) 2004 Philips Semiconductors + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + */ +.EQU VICIrqStatus, 0xFFFFF000 + +#if defined(CONFIG_ARCH_LPC22xx) + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + ldr \irqstat, =(VICIrqStatus) @ load address of interrupt pending + ldr \irqstat, [\irqstat] @ get the register content + + mov \irqnr, #0 +1001: + tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #NR_IRQS + bcc 1001b +1002: /* EQ will be set if we reach 32 */ + .endm + + .macro irq_prio_table + .endm +#endif diff --git a/include/asm-arm/arch-lpc22xx/hardware.h b/include/asm-arm/arch-lpc22xx/hardware.h new file mode 100644 index 00000000..858e4121 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/hardware.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/hardware.h + * + * Copyright (C) 2004 Philips Semiconductors + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#ifndef __ASSEMBLY__ + +#define HARD_RESET_NOW() + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() + +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (1) + +#endif + +#define LPC22xx_MEM_SIZE (CONFIG_DRAM_SIZE) +#define MEM_SIZE LPC22xx_MEM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE + +#endif /* END OF __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-lpc22xx/io.h b/include/asm-arm/arch-lpc22xx/io.h new file mode 100644 index 00000000..79aacf66 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/io.h @@ -0,0 +1,66 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/io.h + * + * Copyright (C) 2004 Philips Semiconductors + * + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff +/* Used in kernel/resource.c */ + +/* + * We have the this routine to use usb host device driver + */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + + +/* + * These macros were copied from arch/armnommu/io.h and are used instead + * of the definitions found there, because we want to do 16/32 bit i/o + * without byte swapping. + * --the + */ + +#undef __io + +#ifndef __iob + #define __iob(a) __io(a) +#endif + +#define outb(v,p) __raw_writeb(v, p) +#define outw(v,p) __raw_writew(v, p) +#define outl(v,p) __raw_writel(v, p) + +#define inb(p) ({ unsigned int __v = __raw_readb(p); __v; }) +#define inw(p) ({ unsigned int __v = __raw_readw(p); __v; }) +#define inl(p) ({ unsigned int __v = __raw_readl(p); __v; }) + +#define outsb(p,d,l) __raw_writesb(p, d, l) +#define outsw(p,d,l) __raw_writesw(p, d, l) +#define outsl(p,d,l) __raw_writesl(p, d, l) + +#define insb(p,d,l) __raw_readsb(p, d, l) +#define insw(p,d,l) __raw_readsw(p, d, l) +#define insl(p,d,l) __raw_readsl(p, d, l) + +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) (1) + + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-lpc22xx/irq.h b/include/asm-arm/arch-lpc22xx/irq.h new file mode 100644 index 00000000..48d83be4 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/irq.h @@ -0,0 +1,22 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/irq.h + * + * Copyright (C) 2004 Philips Semiconductors + */ +#ifndef __LPC22xx_irq_h +#define __LPC22xx_irq_h + +#include +#include +#include +#include + +extern unsigned int fixup_irq(int i); + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void lpc22xx_init_irq(void); + +#define irq_init_irq lpc22xx_init_irq + +#endif diff --git a/include/asm-arm/arch-lpc22xx/irqs.h b/include/asm-arm/arch-lpc22xx/irqs.h new file mode 100644 index 00000000..d5f45571 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/irqs.h @@ -0,0 +1,45 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/irqs.h + * + * Copyright (C) 2004 Philips Semiconductors + * + * IRQ number definition + * All IRQ numbers of the LPC22xx CPUs. + * + */ + +#ifndef __LPC22xx_irqs_h +#define __LPC22xx_irqs_h 1 + +#define NR_IRQS 28 + +#define LPC22xx_INTERRUPT_WDINT 0 /* Watchdog int. 0 */ +#define LPC22xx_INTERRUPT_RSV0 1 /* Reserved int. 1 */ +#define LPC22xx_INTERRUPT_DBGRX 2 /* Embedded ICE DbgCommRx receive */ +#define LPC22xx_INTERRUPT_DBGTX 3 /* Embedded ICE DbgCommRx Transmit*/ +#define LPC22xx_INTERRUPT_TIMER0 4 /* Timer 0 */ +#define LPC22xx_INTERRUPT_TIMER1 5 /* Timer 1 */ +#define LPC22xx_INTERRUPT_UART0 6 /* UART 0 */ +#define LPC22xx_INTERRUPT_UART1 7 /* UART 1 */ +#define LPC22xx_INTERRUPT_PWM0 8 /* PWM */ +#define LPC22xx_INTERRUPT_I2C 9 /* I2C */ +#define LPC22xx_INTERRUPT_SPI0 10 /* SPI0 */ +#define LPC22xx_INTERRUPT_SPI1 11 /* SPI1 */ +#define LPC22xx_INTERRUPT_PLL 12 /* PLL */ +#define LPC22xx_INTERRUPT_RTC 13 /* RTC */ +#define LPC22xx_INTERRUPT_EINT0 14 /* Externel Interrupt 0 */ +#define LPC22xx_INTERRUPT_EINT1 15 /* Externel Interrupt 1 */ +#define LPC22xx_INTERRUPT_EINT2 16 /* Externel Interrupt 2 */ +#define LPC22xx_INTERRUPT_EINT3 17 /* Externel Interrupt 3 */ +#define LPC22xx_INTERRUPT_ADC 18 /* AD Converter */ +#define LPC22xx_INTERRUPT_CANERR 19 /* CAN LUTerr interrupt */ +#define LPC22xx_INTERRUPT_CAN1TX 20 /* CAN1 Tx interrupt */ +#define LPC22xx_INTERRUPT_CAN1RX 21 /* CAN1 Rx interrupt */ +#define LPC22xx_INTERRUPT_CAN2TX 22 /* CAN2 Tx interrupt */ +#define LPC22xx_INTERRUPT_CAN2RX 23 /* CAN2 Rx interrupt */ +#define LPC22xx_INTERRUPT_CAN3TX 24 /* CAN1 Tx interrupt */ +#define LPC22xx_INTERRUPT_CAN3RX 25 /* CAN1 Rx interrupt */ +#define LPC22xx_INTERRUPT_CAN4TX 26 /* CAN2 Tx interrupt */ +#define LPC22xx_INTERRUPT_CAN4RX 27 /* CAN2 Rx interrupt */ + +#endif /* End of __irqs_h */ diff --git a/include/asm-arm/arch-lpc22xx/keyboard.h b/include/asm-arm/arch-lpc22xx/keyboard.h new file mode 100644 index 00000000..614acf3a --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/keyboard.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/keyboard.h + * + * Copyright (C) 2004 Philips Semiconductors + * + */ +#ifndef __ASM_ARMNOMMU_ARCH_LPC22xx_KEYBOARD_H +#define __ASM_ARMNOMMU_ARCH_LPC22xx_KEYBOARD_H + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) +#define kbd_translate(sc,kcp,rm) ({ *(kcp) = (sc); 1; }) +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) +#define kbd_init_hw() +#define kbd_enable_irq() +#define kbd_disable_irq() + +#endif /* __ASM_ARMNOMMU_ARCH_LPC22xx_KEYBOARD_H */ diff --git a/include/asm-arm/arch-lpc22xx/log b/include/asm-arm/arch-lpc22xx/log new file mode 100644 index 00000000..d7bdb34b --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/log @@ -0,0 +1,944 @@ +1,474c1,468 +< /* old +< * linux/include/asm-arm/arch-lpc22xx/lpc22xx.h +< * +< * Copyright (C) 2004 Philips Semiconductors +< */ +< +< #ifndef __ASM_ARCH_LPC22xx_H +< #define __ASM_ARCH_LPC22xx_H +< +< /* EXTERNAL MEMORY CONTROLLER (EMC) */ +< #define BCFG0 (*((volatile unsigned int *) 0xFFE00000)) /* lpc22xx only */ +< #define BCFG1 (*((volatile unsigned int *) 0xFFE00004)) /* lpc22xx only */ +< #define BCFG2 (*((volatile unsigned int *) 0xFFE00008)) /* lpc22xx only */ +< #define BCFG3 (*((volatile unsigned int *) 0xFFE0000C)) /* lpc22xx only */ +< +< /* External Interrupts */ +< #define EXTINT (*((volatile unsigned char *) 0xE01FC140)) +< #define EXTWAKE (*((volatile unsigned char *) 0xE01FC144)) +< #ifdef CONFIG_ARCH_LPC22xx +< #define EXTMODE (*((volatile unsigned char *) 0xE01FC148)) /* no in lpc210x*/ +< #define EXTPOLAR (*((volatile unsigned char *) 0xE01FC14C)) /* no in lpc210x*/ +< #endif +< +< /* SMemory mapping control. */ +< #define MEMMAP (*((volatile unsigned char *) 0xE01FC040)) +< +< /* Phase Locked Loop (PLL) */ +< #define PLLCON (*((volatile unsigned char *) 0xE01FC080)) +< #define PLLCFG (*((volatile unsigned char *) 0xE01FC084)) +< #define PLLSTAT (*((volatile unsigned short*) 0xE01FC088)) +< #define PLLFEED (*((volatile unsigned char *) 0xE01FC08C)) +< +< /* Power Control */ +< #define PCON (*((volatile unsigned char *) 0xE01FC0C0)) +< #define PCONP (*((volatile unsigned long *) 0xE01FC0C4)) +< +< /* VPB Divider */ +< #define VPBDIV (*((volatile unsigned char *) 0xE01FC100)) +< +< /* Memory Accelerator Module (MAM) */ +< #define MAMCR (*((volatile unsigned char *) 0xE01FC000)) +< #define MAMTIM (*((volatile unsigned char *) 0xE01FC004)) +< +< /* Vectored Interrupt Controller (VIC) */ +< #define VICIRQStatus (*((volatile unsigned long *) 0xFFFFF000)) +< #define VICFIQStatus (*((volatile unsigned long *) 0xFFFFF004)) +< #define VICRawIntr (*((volatile unsigned long *) 0xFFFFF008)) +< #define VICIntSelect (*((volatile unsigned long *) 0xFFFFF00C)) +< #define VICIntEnable (*((volatile unsigned long *) 0xFFFFF010)) +< #define VICIntEnClr (*((volatile unsigned long *) 0xFFFFF014)) +< #define VICSoftInt (*((volatile unsigned long *) 0xFFFFF018)) +< #define VICSoftIntClear (*((volatile unsigned long *) 0xFFFFF01C)) +< #define VICProtection (*((volatile unsigned long *) 0xFFFFF020)) +< #define VICVectAddr (*((volatile unsigned long *) 0xFFFFF030)) +< #define VICDefVectAddr (*((volatile unsigned long *) 0xFFFFF034)) +< #define VICVectAddr0 (*((volatile unsigned long *) 0xFFFFF100)) +< #define VICVectAddr1 (*((volatile unsigned long *) 0xFFFFF104)) +< #define VICVectAddr2 (*((volatile unsigned long *) 0xFFFFF108)) +< #define VICVectAddr3 (*((volatile unsigned long *) 0xFFFFF10C)) +< #define VICVectAddr4 (*((volatile unsigned long *) 0xFFFFF110)) +< #define VICVectAddr5 (*((volatile unsigned long *) 0xFFFFF114)) +< #define VICVectAddr6 (*((volatile unsigned long *) 0xFFFFF118)) +< #define VICVectAddr7 (*((volatile unsigned long *) 0xFFFFF11C)) +< #define VICVectAddr8 (*((volatile unsigned long *) 0xFFFFF120)) +< #define VICVectAddr9 (*((volatile unsigned long *) 0xFFFFF124)) +< #define VICVectAddr10 (*((volatile unsigned long *) 0xFFFFF128)) +< #define VICVectAddr11 (*((volatile unsigned long *) 0xFFFFF12C)) +< #define VICVectAddr12 (*((volatile unsigned long *) 0xFFFFF130)) +< #define VICVectAddr13 (*((volatile unsigned long *) 0xFFFFF134)) +< #define VICVectAddr14 (*((volatile unsigned long *) 0xFFFFF138)) +< #define VICVectAddr15 (*((volatile unsigned long *) 0xFFFFF13C)) +< #define VICVectCntl0 (*((volatile unsigned long *) 0xFFFFF200)) +< #define VICVectCntl1 (*((volatile unsigned long *) 0xFFFFF204)) +< #define VICVectCntl2 (*((volatile unsigned long *) 0xFFFFF208)) +< #define VICVectCntl3 (*((volatile unsigned long *) 0xFFFFF20C)) +< #define VICVectCntl4 (*((volatile unsigned long *) 0xFFFFF210)) +< #define VICVectCntl5 (*((volatile unsigned long *) 0xFFFFF214)) +< #define VICVectCntl6 (*((volatile unsigned long *) 0xFFFFF218)) +< #define VICVectCntl7 (*((volatile unsigned long *) 0xFFFFF21C)) +< #define VICVectCntl8 (*((volatile unsigned long *) 0xFFFFF220)) +< #define VICVectCntl9 (*((volatile unsigned long *) 0xFFFFF224)) +< #define VICVectCntl10 (*((volatile unsigned long *) 0xFFFFF228)) +< #define VICVectCntl11 (*((volatile unsigned long *) 0xFFFFF22C)) +< #define VICVectCntl12 (*((volatile unsigned long *) 0xFFFFF230)) +< #define VICVectCntl13 (*((volatile unsigned long *) 0xFFFFF234)) +< #define VICVectCntl14 (*((volatile unsigned long *) 0xFFFFF238)) +< #define VICVectCntl15 (*((volatile unsigned long *) 0xFFFFF23C)) +< +< /* Pin Connect Block */ +< #define PINSEL0 (*((volatile unsigned long *) 0xE002C000)) +< #define PINSEL1 (*((volatile unsigned long *) 0xE002C004)) +< #ifdef CONFIG_ARCH_LPC22xx +< #define PINSEL2 (*((volatile unsigned long *) 0xE002C014)) /* no in lpc210x*/ +< #endif +< +< /* General Purpose Input/Output (GPIO) */ +< #ifndef CONFIG_ARCH_LPC22xx +< +< #define IOPIN (*((volatile unsigned long *) 0xE0028000)) /* lpc210x only */ +< #define IOSET (*((volatile unsigned long *) 0xE0028004)) /* lpc210x only */ +< #define IODIR (*((volatile unsigned long *) 0xE0028008)) /* lpc210x only */ +< #define IOCLR (*((volatile unsigned long *) 0xE002800C)) /* lpc210x only */ +< +< #endif +< +< #ifdef CONFIG_ARCH_LPC22xx +< #define IO0PIN (*((volatile unsigned long *) 0xE0028000)) /* no in lpc210x*/ +< #define IO0SET (*((volatile unsigned long *) 0xE0028004)) /* no in lpc210x*/ +< #define IO0DIR (*((volatile unsigned long *) 0xE0028008)) /* no in lpc210x*/ +< #define IO0CLR (*((volatile unsigned long *) 0xE002800C)) /* no in lpc210x*/ +< +< #define IO1PIN (*((volatile unsigned long *) 0xE0028010)) /* no in lpc210x*/ +< #define IO1SET (*((volatile unsigned long *) 0xE0028014)) /* no in lpc210x*/ +< #define IO1DIR (*((volatile unsigned long *) 0xE0028018)) /* no in lpc210x*/ +< #define IO1CLR (*((volatile unsigned long *) 0xE002801C)) /* no in lpc210x*/ +< #endif +< +< #ifdef CONFIG_ARCH_LPC22xx +< +< #define IO2PIN (*((volatile unsigned long *) 0xE0028020)) /* lpc22xx only */ +< #define IO2SET (*((volatile unsigned long *) 0xE0028024)) /* lpc22xx only */ +< #define IO2DIR (*((volatile unsigned long *) 0xE0028028)) /* lpc22xx only */ +< #define IO2CLR (*((volatile unsigned long *) 0xE002802C)) /* lpc22xx only */ +< +< #define IO3PIN (*((volatile unsigned long *) 0xE0028030)) /* lpc22xx only */ +< #define IO3SET (*((volatile unsigned long *) 0xE0028034)) /* lpc22xx only */ +< #define IO3DIR (*((volatile unsigned long *) 0xE0028038)) /* lpc22xx only */ +< #define IO3CLR (*((volatile unsigned long *) 0xE002803C)) /* lpc22xx only */ +< +< #endif +< +< /* Universal Asynchronous Receiver Transmitter 0 (UART0) */ +< #define U0RBR (*((volatile unsigned char *) 0xE000C000)) +< #define U0THR (*((volatile unsigned char *) 0xE000C000)) +< #define U0IER (*((volatile unsigned char *) 0xE000C004)) +< #define U0IIR (*((volatile unsigned char *) 0xE000C008)) +< #define U0FCR (*((volatile unsigned char *) 0xE000C008)) +< #define U0LCR (*((volatile unsigned char *) 0xE000C00C)) +< #define U0LSR (*((volatile unsigned char *) 0xE000C014)) +< #define U0SCR (*((volatile unsigned char *) 0xE000C01C)) +< #define U0DLL (*((volatile unsigned char *) 0xE000C000)) +< #define U0DLM (*((volatile unsigned char *) 0xE000C004)) +< +< /* Universal Asynchronous Receiver Transmitter 1 (UART1) */ +< #define U1RBR (*((volatile unsigned char *) 0xE0010000)) +< #define U1THR (*((volatile unsigned char *) 0xE0010000)) +< #define U1IER (*((volatile unsigned char *) 0xE0010004)) +< #define U1IIR (*((volatile unsigned char *) 0xE0010008)) +< #define U1FCR (*((volatile unsigned char *) 0xE0010008)) +< #define U1LCR (*((volatile unsigned char *) 0xE001000C)) +< #define U1MCR (*((volatile unsigned char *) 0xE0010010)) +< #define U1LSR (*((volatile unsigned char *) 0xE0010014)) +< #define U1MSR (*((volatile unsigned char *) 0xE0010018)) +< #define U1SCR (*((volatile unsigned char *) 0xE001001C)) +< #define U1DLL (*((volatile unsigned char *) 0xE0010000)) +< #define U1DLM (*((volatile unsigned char *) 0xE0010004)) +< +< /* I2C (8/16 bit data bus) */ +< #define I2CONSET (*((volatile unsigned char *) 0xE001C000)) +< #define I2STAT (*((volatile unsigned char *) 0xE001C004)) +< #define I2DAT (*((volatile unsigned char *) 0xE001C008)) +< #define I2ADR (*((volatile unsigned char *) 0xE001C00C)) +< #define I2SCLH (*((volatile unsigned short *) 0xE001C010)) +< #define I2SCLL (*((volatile unsigned short *) 0xE001C014)) +< #define I2CONCLR (*((volatile unsigned char *) 0xE001C018)) +< +< /* SPI (Serial Peripheral Interface) */ +< /* only for lpc210x*/ +< #define SPI_SPCR (*((volatile unsigned char *) 0xE0020000)) +< #define SPI_SPSR (*((volatile unsigned char *) 0xE0020004)) +< #define SPI_SPDR (*((volatile unsigned char *) 0xE0020008)) +< #define SPI_SPCCR (*((volatile unsigned char *) 0xE002000C)) +< #define SPI_SPINT (*((volatile unsigned char *) 0xE002001C)) +< +< #ifdef CONFIG_ARCH_LPC22xx +< #define S0PCR (*((volatile unsigned char *) 0xE0020000)) /* no in lpc210x*/ +< #define S0PSR (*((volatile unsigned char *) 0xE0020004)) /* no in lpc210x*/ +< #define S0PDR (*((volatile unsigned char *) 0xE0020008)) /* no in lpc210x*/ +< #define S0PCCR (*((volatile unsigned char *) 0xE002000C)) /* no in lpc210x*/ +< #define S0PINT (*((volatile unsigned char *) 0xE002001C)) /* no in lpc210x*/ +< +< #define S1PCR (*((volatile unsigned char *) 0xE0030000)) /* no in lpc210x*/ +< #define S1PSR (*((volatile unsigned char *) 0xE0030004)) /* no in lpc210x*/ +< #define S1PDR (*((volatile unsigned char *) 0xE0030008)) /* no in lpc210x*/ +< #define S1PCCR (*((volatile unsigned char *) 0xE003000C)) /* no in lpc210x*/ +< #define S1PINT (*((volatile unsigned char *) 0xE003001C)) /* no in lpc210x*/ +< #endif +< /* CAN CONTROLLERS AND ACCEPTANCE FILTER */ +< #define CAN1MOD (*((volatile unsigned long *) 0xE0044000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1CMR (*((volatile unsigned long *) 0xE0044004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1GSR (*((volatile unsigned long *) 0xE0044008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1ICR (*((volatile unsigned long *) 0xE004400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1IER (*((volatile unsigned long *) 0xE0044010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1BTR (*((volatile unsigned long *) 0xE0044014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1EWL (*((volatile unsigned long *) 0xE004401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1SR (*((volatile unsigned long *) 0xE0044020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1RFS (*((volatile unsigned long *) 0xE0044024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1RDA (*((volatile unsigned long *) 0xE0044028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1RDB (*((volatile unsigned long *) 0xE004402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TFI1 (*((volatile unsigned long *) 0xE0044030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TID1 (*((volatile unsigned long *) 0xE0044034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDA1 (*((volatile unsigned long *) 0xE0044038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDB1 (*((volatile unsigned long *) 0xE004403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TFI2 (*((volatile unsigned long *) 0xE0044040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TID2 (*((volatile unsigned long *) 0xE0044044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDA2 (*((volatile unsigned long *) 0xE0044048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDB2 (*((volatile unsigned long *) 0xE004404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TFI3 (*((volatile unsigned long *) 0xE0044050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TID3 (*((volatile unsigned long *) 0xE0044054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDA3 (*((volatile unsigned long *) 0xE0044058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN1TDB3 (*((volatile unsigned long *) 0xE004405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #define CAN2MOD (*((volatile unsigned long *) 0xE0048000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2CMR (*((volatile unsigned long *) 0xE0048004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2GSR (*((volatile unsigned long *) 0xE0048008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2ICR (*((volatile unsigned long *) 0xE004800C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2IER (*((volatile unsigned long *) 0xE0048010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2BTR (*((volatile unsigned long *) 0xE0048014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2EWL (*((volatile unsigned long *) 0xE004801C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2SR (*((volatile unsigned long *) 0xE0048020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2RFS (*((volatile unsigned long *) 0xE0048024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2RDA (*((volatile unsigned long *) 0xE0048028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2RDB (*((volatile unsigned long *) 0xE004802C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TFI1 (*((volatile unsigned long *) 0xE0048030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TID1 (*((volatile unsigned long *) 0xE0048034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDA1 (*((volatile unsigned long *) 0xE0048038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDB1 (*((volatile unsigned long *) 0xE004803C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TFI2 (*((volatile unsigned long *) 0xE0048040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TID2 (*((volatile unsigned long *) 0xE0048044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDA2 (*((volatile unsigned long *) 0xE0048048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDB2 (*((volatile unsigned long *) 0xE004804C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TFI3 (*((volatile unsigned long *) 0xE0048050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TID3 (*((volatile unsigned long *) 0xE0048054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDA3 (*((volatile unsigned long *) 0xE0048058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN2TDB3 (*((volatile unsigned long *) 0xE004805C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #define CAN3MOD (*((volatile unsigned long *) 0xE004C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3CMR (*((volatile unsigned long *) 0xE004C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3GSR (*((volatile unsigned long *) 0xE004C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3ICR (*((volatile unsigned long *) 0xE004C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3IER (*((volatile unsigned long *) 0xE004C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3BTR (*((volatile unsigned long *) 0xE004C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3EWL (*((volatile unsigned long *) 0xE004C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3SR (*((volatile unsigned long *) 0xE004C020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3RFS (*((volatile unsigned long *) 0xE004C024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3RDA (*((volatile unsigned long *) 0xE004C028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3RDB (*((volatile unsigned long *) 0xE004C02C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TFI1 (*((volatile unsigned long *) 0xE004C030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TID1 (*((volatile unsigned long *) 0xE004C034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDA1 (*((volatile unsigned long *) 0xE004C038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDB1 (*((volatile unsigned long *) 0xE004C03C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TFI2 (*((volatile unsigned long *) 0xE004C040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TID2 (*((volatile unsigned long *) 0xE004C044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDA2 (*((volatile unsigned long *) 0xE004C048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDB2 (*((volatile unsigned long *) 0xE004C04C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TFI3 (*((volatile unsigned long *) 0xE004C050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TID3 (*((volatile unsigned long *) 0xE004C054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDA3 (*((volatile unsigned long *) 0xE004C058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN3TDB3 (*((volatile unsigned long *) 0xE004C05C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #define CAN4MOD (*((volatile unsigned long *) 0xE0050000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4CMR (*((volatile unsigned long *) 0xE0050004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4GSR (*((volatile unsigned long *) 0xE0050008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4ICR (*((volatile unsigned long *) 0xE005000C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4IER (*((volatile unsigned long *) 0xE0050010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4BTR (*((volatile unsigned long *) 0xE0050014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4EWL (*((volatile unsigned long *) 0xE005001C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4SR (*((volatile unsigned long *) 0xE0050020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4RFS (*((volatile unsigned long *) 0xE0050024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4RDA (*((volatile unsigned long *) 0xE0050028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4RDB (*((volatile unsigned long *) 0xE005002C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TFI1 (*((volatile unsigned long *) 0xE0050030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TID1 (*((volatile unsigned long *) 0xE0050034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDA1 (*((volatile unsigned long *) 0xE0050038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDB1 (*((volatile unsigned long *) 0xE005003C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TFI2 (*((volatile unsigned long *) 0xE0050040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TID2 (*((volatile unsigned long *) 0xE0050044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDA2 (*((volatile unsigned long *) 0xE0050048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDB2 (*((volatile unsigned long *) 0xE005004C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TFI3 (*((volatile unsigned long *) 0xE0050050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TID3 (*((volatile unsigned long *) 0xE0050054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDA3 (*((volatile unsigned long *) 0xE0050058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN4TDB3 (*((volatile unsigned long *) 0xE005005C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #define CAN5MOD (*((volatile unsigned long *) 0xE0054000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5CMR (*((volatile unsigned long *) 0xE0054004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5GSR (*((volatile unsigned long *) 0xE0054008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5ICR (*((volatile unsigned long *) 0xE005400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5IER (*((volatile unsigned long *) 0xE0054010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5BTR (*((volatile unsigned long *) 0xE0054014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5EWL (*((volatile unsigned long *) 0xE005401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5SR (*((volatile unsigned long *) 0xE0054020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5RFS (*((volatile unsigned long *) 0xE0054024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5RDA (*((volatile unsigned long *) 0xE0054028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5RDB (*((volatile unsigned long *) 0xE005402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TFI1 (*((volatile unsigned long *) 0xE0054030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TID1 (*((volatile unsigned long *) 0xE0054034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDA1 (*((volatile unsigned long *) 0xE0054038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDB1 (*((volatile unsigned long *) 0xE005403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TFI2 (*((volatile unsigned long *) 0xE0054040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TID2 (*((volatile unsigned long *) 0xE0054044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDA2 (*((volatile unsigned long *) 0xE0054048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDB2 (*((volatile unsigned long *) 0xE005404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TFI3 (*((volatile unsigned long *) 0xE0054050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TID3 (*((volatile unsigned long *) 0xE0054054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDA3 (*((volatile unsigned long *) 0xE0054058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CAN5TDB3 (*((volatile unsigned long *) 0xE005405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #ifdef CONFIG_ARCH_LPC22xx +< #define CAN6MOD (*((volatile unsigned long *) 0xE0058000)) /* lpc2292\lpc2294 only */ +< #define CAN6CMR (*((volatile unsigned long *) 0xE0058004)) /* lpc2292\lpc2294 only */ +< #define CAN6GSR (*((volatile unsigned long *) 0xE0058008)) /* lpc2292\lpc2294 only */ +< #define CAN6ICR (*((volatile unsigned long *) 0xE005800C)) /* lpc2292\lpc2294 only */ +< #define CAN6IER (*((volatile unsigned long *) 0xE0058010)) /* lpc2292\lpc2294 only */ +< #define CAN6BTR (*((volatile unsigned long *) 0xE0058014)) /* lpc2292\lpc2294 only */ +< #define CAN6EWL (*((volatile unsigned long *) 0xE005801C)) /* lpc2292\lpc2294 only */ +< #define CAN6SR (*((volatile unsigned long *) 0xE0058020)) /* lpc2292\lpc2294 only */ +< #define CAN6RFS (*((volatile unsigned long *) 0xE0058024)) /* lpc2292\lpc2294 only */ +< #define CAN6RDA (*((volatile unsigned long *) 0xE0058028)) /* lpc2292\lpc2294 only */ +< #define CAN6RDB (*((volatile unsigned long *) 0xE005802C)) /* lpc2292\lpc2294 only */ +< #define CAN6TFI1 (*((volatile unsigned long *) 0xE0058030)) /* lpc2292\lpc2294 only */ +< #define CAN6TID1 (*((volatile unsigned long *) 0xE0058034)) /* lpc2292\lpc2294 only */ +< #define CAN6TDA1 (*((volatile unsigned long *) 0xE0058038)) /* lpc2292\lpc2294 only */ +< #define CAN6TDB1 (*((volatile unsigned long *) 0xE005803C)) /* lpc2292\lpc2294 only */ +< #define CAN6TFI2 (*((volatile unsigned long *) 0xE0058040)) /* lpc2292\lpc2294 only */ +< #define CAN6TID2 (*((volatile unsigned long *) 0xE0058044)) /* lpc2292\lpc2294 only */ +< #define CAN6TDA2 (*((volatile unsigned long *) 0xE0058048)) /* lpc2292\lpc2294 only */ +< #define CAN6TDB2 (*((volatile unsigned long *) 0xE005804C)) /* lpc2292\lpc2294 only */ +< #define CAN6TFI3 (*((volatile unsigned long *) 0xE0058050)) /* lpc2292\lpc2294 only */ +< #define CAN6TID3 (*((volatile unsigned long *) 0xE0058054)) /* lpc2292\lpc2294 only */ +< #define CAN6TDA3 (*((volatile unsigned long *) 0xE0058058)) /* lpc2292\lpc2294 only */ +< #define CAN6TDB3 (*((volatile unsigned long *) 0xE005805C)) /* lpc2292\lpc2294 only */ +< #endif +< +< #define CANTxSR (*((volatile unsigned long *) 0xE0040000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANRxSR (*((volatile unsigned long *) 0xE0040004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANMSR (*((volatile unsigned long *) 0xE0040008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< +< #define CANAFMR (*((volatile unsigned long *) 0xE003C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANSFF_sa (*((volatile unsigned long *) 0xE003C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANSFF_GRP_sa (*((volatile unsigned long *) 0xE003C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANEFF_sa (*((volatile unsigned long *) 0xE003C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANEFF_GRP_sa (*((volatile unsigned long *) 0xE003C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANENDofTable (*((volatile unsigned long *) 0xE003C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANLUTerrAd (*((volatile unsigned long *) 0xE003C018)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< #define CANLUTerr (*((volatile unsigned long *) 0xE003C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +< /* CAN Acceptance Filter RAM */ +< #define CANAFRAM (*((volatile unsigned long *) 0xE0038000)) +< +< +< /* Timer 0 */ +< #define T0IR (*((volatile unsigned long *) 0xE0004000)) +< #define T0TCR (*((volatile unsigned long *) 0xE0004004)) +< #define T0TC (*((volatile unsigned long *) 0xE0004008)) +< #define T0PR (*((volatile unsigned long *) 0xE000400C)) +< #define T0PC (*((volatile unsigned long *) 0xE0004010)) +< #define T0MCR (*((volatile unsigned long *) 0xE0004014)) +< #define T0MR0 (*((volatile unsigned long *) 0xE0004018)) +< #define T0MR1 (*((volatile unsigned long *) 0xE000401C)) +< #define T0MR2 (*((volatile unsigned long *) 0xE0004020)) +< #define T0MR3 (*((volatile unsigned long *) 0xE0004024)) +< #define T0CCR (*((volatile unsigned long *) 0xE0004028)) +< #define T0CR0 (*((volatile unsigned long *) 0xE000402C)) +< #define T0CR1 (*((volatile unsigned long *) 0xE0004030)) +< #define T0CR2 (*((volatile unsigned long *) 0xE0004034)) +< #define T0CR3 (*((volatile unsigned long *) 0xE0004038)) +< #define T0EMR (*((volatile unsigned long *) 0xE000403C)) +< +< /* Timer 1 */ +< #define T1IR (*((volatile unsigned long *) 0xE0008000)) +< #define T1TCR (*((volatile unsigned long *) 0xE0008004)) +< #define T1TC (*((volatile unsigned long *) 0xE0008008)) +< #define T1PR (*((volatile unsigned long *) 0xE000800C)) +< #define T1PC (*((volatile unsigned long *) 0xE0008010)) +< #define T1MCR (*((volatile unsigned long *) 0xE0008014)) +< #define T1MR0 (*((volatile unsigned long *) 0xE0008018)) +< #define T1MR1 (*((volatile unsigned long *) 0xE000801C)) +< #define T1MR2 (*((volatile unsigned long *) 0xE0008020)) +< #define T1MR3 (*((volatile unsigned long *) 0xE0008024)) +< #define T1CCR (*((volatile unsigned long *) 0xE0008028)) +< #define T1CR0 (*((volatile unsigned long *) 0xE000802C)) +< #define T1CR1 (*((volatile unsigned long *) 0xE0008030)) +< #define T1CR2 (*((volatile unsigned long *) 0xE0008034)) +< #define T1CR3 (*((volatile unsigned long *) 0xE0008038)) +< #define T1EMR (*((volatile unsigned long *) 0xE000803C)) +< +< /* Pulse Width Modulator (PWM) */ +< #define PWMIR (*((volatile unsigned long *) 0xE0014000)) +< #define PWMTCR (*((volatile unsigned long *) 0xE0014004)) +< #define PWMTC (*((volatile unsigned long *) 0xE0014008)) +< #define PWMPR (*((volatile unsigned long *) 0xE001400C)) +< #define PWMPC (*((volatile unsigned long *) 0xE0014010)) +< #define PWMMCR (*((volatile unsigned long *) 0xE0014014)) +< #define PWMMR0 (*((volatile unsigned long *) 0xE0014018)) +< #define PWMMR1 (*((volatile unsigned long *) 0xE001401C)) +< #define PWMMR2 (*((volatile unsigned long *) 0xE0014020)) +< #define PWMMR3 (*((volatile unsigned long *) 0xE0014024)) +< #define PWMMR4 (*((volatile unsigned long *) 0xE0014040)) +< #define PWMMR5 (*((volatile unsigned long *) 0xE0014044)) +< #define PWMMR6 (*((volatile unsigned long *) 0xE0014048)) +< #define PWMPCR (*((volatile unsigned long *) 0xE001404C)) +< #define PWMLER (*((volatile unsigned long *) 0xE0014050)) +< +< /* A/D CONVERTER */ +< #ifndef CONFIG_ARCH_LPC2104 +< #define ADCR (*((volatile unsigned long *) 0xE0034000)) /* no in lpc210x*/ +< #define ADDR (*((volatile unsigned long *) 0xE0034004)) /* no in lpc210x*/ +< #endif +< +< /* Real Time Clock */ +< #define ILR (*((volatile unsigned char *) 0xE0024000)) +< #define CTC (*((volatile unsigned short*) 0xE0024004)) +< #define CCR (*((volatile unsigned char *) 0xE0024008)) +< #define CIIR (*((volatile unsigned char *) 0xE002400C)) +< #define AMR (*((volatile unsigned char *) 0xE0024010)) +< #define CTIME0 (*((volatile unsigned long *) 0xE0024014)) +< #define CTIME1 (*((volatile unsigned long *) 0xE0024018)) +< #define CTIME2 (*((volatile unsigned long *) 0xE002401C)) +< #define SEC (*((volatile unsigned char *) 0xE0024020)) +< #define MIN (*((volatile unsigned char *) 0xE0024024)) +< #define HOUR (*((volatile unsigned char *) 0xE0024028)) +< #define DOM (*((volatile unsigned char *) 0xE002402C)) +< #define DOW (*((volatile unsigned char *) 0xE0024030)) +< #define DOY (*((volatile unsigned short*) 0xE0024034)) +< #define MONTH (*((volatile unsigned char *) 0xE0024038)) +< #define YEAR (*((volatile unsigned short*) 0xE002403C)) +< #define ALSEC (*((volatile unsigned char *) 0xE0024060)) +< #define ALMIN (*((volatile unsigned char *) 0xE0024064)) +< #define ALHOUR (*((volatile unsigned char *) 0xE0024068)) +< #define ALDOM (*((volatile unsigned char *) 0xE002406C)) +< #define ALDOW (*((volatile unsigned char *) 0xE0024070)) +< #define ALDOY (*((volatile unsigned short*) 0xE0024074)) +< #define ALMON (*((volatile unsigned char *) 0xE0024078)) +< #define ALYEAR (*((volatile unsigned short*) 0xE002407C)) +< #define PREINT (*((volatile unsigned short*) 0xE0024080)) +< #define PREFRAC (*((volatile unsigned short*) 0xE0024084)) +< +< /* Watchdog */ +< #define WDMOD (*((volatile unsigned char *) 0xE0000000)) +< #define WDTC (*((volatile unsigned long *) 0xE0000004)) +< #define WDFEED (*((volatile unsigned char *) 0xE0000008)) +< #define WDTV (*((volatile unsigned long *) 0xE000000C)) +< +< /* +< Register define for constant +< */ +< #define REG_U0RBR 0xE000C000 +< #define REG_U1RBR 0xE0010000 +< +< /* PLL */ +< #define REG_PLLCON 0xE01FC080 +< #define REG_PLLCFG 0xE01FC084 +< #define REG_PLLSTAT 0xE01FC088 +< #define REG_PLLFEED 0xE01FC08C +< +< /* Power Control */ +< +< #define REG_PCON 0xE01FC0C0 +< #define REG_PCOMP 0xE01FC0C4 +< #define REG_PINSEL0 0xE002C000 +< #define REG_MEMMAP 0xE01FC040 +< #define REG_PLLSTAT 0xE01FC088 +< #define REG_VPBDIV 0xE01FC100 +< +< +< +< #define LPC22xx_Fcclk CONFIG_ARM_CLK /* system clk frequecy,<=60Mhz, defined in system configuration */ +< #define LPC22xx_Fcco LPC22xx_Fcclk * 4 +< #define LPC22xx_Fpclk (LPC22xx_Fcclk /4) *1 /*VPB clk frequency,1,1/2,1/4 times of Fcclk */ +< +< #endif +< /********************************************************************************************************* +< ** End Of File +< ********************************************************************************************************/ +--- +> +> #define __ASM_ARCH_LPC22xx_H +> +> /* EXTERNAL MEMORY CONTROLLER (EMC) */ +> #define BCFG0 (*((volatile unsigned int *) 0xFFE00000)) /* lpc22xx only */ +> #define BCFG1 (*((volatile unsigned int *) 0xFFE00004)) /* lpc22xx only */ +> #define BCFG2 (*((volatile unsigned int *) 0xFFE00008)) /* lpc22xx only */ +> #define BCFG3 (*((volatile unsigned int *) 0xFFE0000C)) /* lpc22xx only */ +> +> /* External Interrupts */ +> #define EXTINT (*((volatile unsigned char *) 0xE01FC140)) +> #define EXTWAKE (*((volatile unsigned char *) 0xE01FC144)) +> #ifdef CONFIG_ARCH_LPC22xx +> #define EXTMODE (*((volatile unsigned char *) 0xE01FC148)) /* no in lpc210x*/ +> #define EXTPOLAR (*((volatile unsigned char *) 0xE01FC14C)) /* no in lpc210x*/ +> #endif +> +> /* SMemory mapping control. */ +> #define MEMMAP (*((volatile unsigned char *) 0xE01FC040)) +> +> /* Phase Locked Loop (PLL) */ +> #define PLLCON (*((volatile unsigned char *) 0xE01FC080)) +> #define PLLCFG (*((volatile unsigned char *) 0xE01FC084)) +> #define PLLSTAT (*((volatile unsigned short*) 0xE01FC088)) +> #define PLLFEED (*((volatile unsigned char *) 0xE01FC08C)) +> +> /* Power Control */ +> #define PCON (*((volatile unsigned char *) 0xE01FC0C0)) +> #define PCONP (*((volatile unsigned long *) 0xE01FC0C4)) +> +> /* VPB Divider */ +> #define VPBDIV (*((volatile unsigned char *) 0xE01FC100)) +> +> /* Memory Accelerator Module (MAM) */ +> #define MAMCR (*((volatile unsigned char *) 0xE01FC000)) +> #define MAMTIM (*((volatile unsigned char *) 0xE01FC004)) +> +> /* Vectored Interrupt Controller (VIC) */ +> #define VICIRQStatus (*((volatile unsigned long *) 0xFFFFF000)) +> #define VICFIQStatus (*((volatile unsigned long *) 0xFFFFF004)) +> #define VICRawIntr (*((volatile unsigned long *) 0xFFFFF008)) +> #define VICIntSelect (*((volatile unsigned long *) 0xFFFFF00C)) +> #define VICIntEnable (*((volatile unsigned long *) 0xFFFFF010)) +> #define VICIntEnClr (*((volatile unsigned long *) 0xFFFFF014)) +> #define VICSoftInt (*((volatile unsigned long *) 0xFFFFF018)) +> #define VICSoftIntClear (*((volatile unsigned long *) 0xFFFFF01C)) +> #define VICProtection (*((volatile unsigned long *) 0xFFFFF020)) +> #define VICVectAddr (*((volatile unsigned long *) 0xFFFFF030)) +> #define VICDefVectAddr (*((volatile unsigned long *) 0xFFFFF034)) +> #define VICVectAddr0 (*((volatile unsigned long *) 0xFFFFF100)) +> #define VICVectAddr1 (*((volatile unsigned long *) 0xFFFFF104)) +> #define VICVectAddr2 (*((volatile unsigned long *) 0xFFFFF108)) +> #define VICVectAddr3 (*((volatile unsigned long *) 0xFFFFF10C)) +> #define VICVectAddr4 (*((volatile unsigned long *) 0xFFFFF110)) +> #define VICVectAddr5 (*((volatile unsigned long *) 0xFFFFF114)) +> #define VICVectAddr6 (*((volatile unsigned long *) 0xFFFFF118)) +> #define VICVectAddr7 (*((volatile unsigned long *) 0xFFFFF11C)) +> #define VICVectAddr8 (*((volatile unsigned long *) 0xFFFFF120)) +> #define VICVectAddr9 (*((volatile unsigned long *) 0xFFFFF124)) +> #define VICVectAddr10 (*((volatile unsigned long *) 0xFFFFF128)) +> #define VICVectAddr11 (*((volatile unsigned long *) 0xFFFFF12C)) +> #define VICVectAddr12 (*((volatile unsigned long *) 0xFFFFF130)) +> #define VICVectAddr13 (*((volatile unsigned long *) 0xFFFFF134)) +> #define VICVectAddr14 (*((volatile unsigned long *) 0xFFFFF138)) +> #define VICVectAddr15 (*((volatile unsigned long *) 0xFFFFF13C)) +> #define VICVectCntl0 (*((volatile unsigned long *) 0xFFFFF200)) +> #define VICVectCntl1 (*((volatile unsigned long *) 0xFFFFF204)) +> #define VICVectCntl2 (*((volatile unsigned long *) 0xFFFFF208)) +> #define VICVectCntl3 (*((volatile unsigned long *) 0xFFFFF20C)) +> #define VICVectCntl4 (*((volatile unsigned long *) 0xFFFFF210)) +> #define VICVectCntl5 (*((volatile unsigned long *) 0xFFFFF214)) +> #define VICVectCntl6 (*((volatile unsigned long *) 0xFFFFF218)) +> #define VICVectCntl7 (*((volatile unsigned long *) 0xFFFFF21C)) +> #define VICVectCntl8 (*((volatile unsigned long *) 0xFFFFF220)) +> #define VICVectCntl9 (*((volatile unsigned long *) 0xFFFFF224)) +> #define VICVectCntl10 (*((volatile unsigned long *) 0xFFFFF228)) +> #define VICVectCntl11 (*((volatile unsigned long *) 0xFFFFF22C)) +> #define VICVectCntl12 (*((volatile unsigned long *) 0xFFFFF230)) +> #define VICVectCntl13 (*((volatile unsigned long *) 0xFFFFF234)) +> #define VICVectCntl14 (*((volatile unsigned long *) 0xFFFFF238)) +> #define VICVectCntl15 (*((volatile unsigned long *) 0xFFFFF23C)) +> +> /* Pin Connect Block */ +> #define PINSEL0 (*((volatile unsigned long *) 0xE002C000)) +> #define PINSEL1 (*((volatile unsigned long *) 0xE002C004)) +> #ifdef CONFIG_ARCH_LPC22xx +> #define PINSEL2 (*((volatile unsigned long *) 0xE002C014)) /* no in lpc210x*/ +> #endif +> +> /* General Purpose Input/Output (GPIO) */ +> #ifndef CONFIG_ARCH_LPC22xx +> +> #define IOPIN (*((volatile unsigned long *) 0xE0028000)) /* lpc210x only */ +> #define IOSET (*((volatile unsigned long *) 0xE0028004)) /* lpc210x only */ +> #define IODIR (*((volatile unsigned long *) 0xE0028008)) /* lpc210x only */ +> #define IOCLR (*((volatile unsigned long *) 0xE002800C)) /* lpc210x only */ +> +> #endif +> +> #ifdef CONFIG_ARCH_LPC22xx +> #define IO0PIN (*((volatile unsigned long *) 0xE0028000)) /* no in lpc210x*/ +> #define IO0SET (*((volatile unsigned long *) 0xE0028004)) /* no in lpc210x*/ +> #define IO0DIR (*((volatile unsigned long *) 0xE0028008)) /* no in lpc210x*/ +> #define IO0CLR (*((volatile unsigned long *) 0xE002800C)) /* no in lpc210x*/ +> +> #define IO1PIN (*((volatile unsigned long *) 0xE0028010)) /* no in lpc210x*/ +> #define IO1SET (*((volatile unsigned long *) 0xE0028014)) /* no in lpc210x*/ +> #define IO1DIR (*((volatile unsigned long *) 0xE0028018)) /* no in lpc210x*/ +> #define IO1CLR (*((volatile unsigned long *) 0xE002801C)) /* no in lpc210x*/ +> #endif +> +> #ifdef CONFIG_ARCH_LPC22xx +> +> #define IO2PIN (*((volatile unsigned long *) 0xE0028020)) /* lpc22xx only */ +> #define IO2SET (*((volatile unsigned long *) 0xE0028024)) /* lpc22xx only */ +> #define IO2DIR (*((volatile unsigned long *) 0xE0028028)) /* lpc22xx only */ +> #define IO2CLR (*((volatile unsigned long *) 0xE002802C)) /* lpc22xx only */ +> +> #define IO3PIN (*((volatile unsigned long *) 0xE0028030)) /* lpc22xx only */ +> #define IO3SET (*((volatile unsigned long *) 0xE0028034)) /* lpc22xx only */ +> #define IO3DIR (*((volatile unsigned long *) 0xE0028038)) /* lpc22xx only */ +> #define IO3CLR (*((volatile unsigned long *) 0xE002803C)) /* lpc22xx only */ +> +> #endif +> +> /* Universal Asynchronous Receiver Transmitter 0 (UART0) */ +> #define U0RBR (*((volatile unsigned char *) 0xE000C000)) +> #define U0THR (*((volatile unsigned char *) 0xE000C000)) +> #define U0IER (*((volatile unsigned char *) 0xE000C004)) +> #define U0IIR (*((volatile unsigned char *) 0xE000C008)) +> #define U0FCR (*((volatile unsigned char *) 0xE000C008)) +> #define U0LCR (*((volatile unsigned char *) 0xE000C00C)) +> #define U0LSR (*((volatile unsigned char *) 0xE000C014)) +> #define U0SCR (*((volatile unsigned char *) 0xE000C01C)) +> #define U0DLL (*((volatile unsigned char *) 0xE000C000)) +> #define U0DLM (*((volatile unsigned char *) 0xE000C004)) +> +> /* Universal Asynchronous Receiver Transmitter 1 (UART1) */ +> #define U1RBR (*((volatile unsigned char *) 0xE0010000)) +> #define U1THR (*((volatile unsigned char *) 0xE0010000)) +> #define U1IER (*((volatile unsigned char *) 0xE0010004)) +> #define U1IIR (*((volatile unsigned char *) 0xE0010008)) +> #define U1FCR (*((volatile unsigned char *) 0xE0010008)) +> #define U1LCR (*((volatile unsigned char *) 0xE001000C)) +> #define U1MCR (*((volatile unsigned char *) 0xE0010010)) +> #define U1LSR (*((volatile unsigned char *) 0xE0010014)) +> #define U1MSR (*((volatile unsigned char *) 0xE0010018)) +> #define U1SCR (*((volatile unsigned char *) 0xE001001C)) +> #define U1DLL (*((volatile unsigned char *) 0xE0010000)) +> #define U1DLM (*((volatile unsigned char *) 0xE0010004)) +> +> /* I2C (8/16 bit data bus) */ +> #define I2CONSET (*((volatile unsigned char *) 0xE001C000)) +> #define I2STAT (*((volatile unsigned char *) 0xE001C004)) +> #define I2DAT (*((volatile unsigned char *) 0xE001C008)) +> #define I2ADR (*((volatile unsigned char *) 0xE001C00C)) +> #define I2SCLH (*((volatile unsigned short *) 0xE001C010)) +> #define I2SCLL (*((volatile unsigned short *) 0xE001C014)) +> #define I2CONCLR (*((volatile unsigned char *) 0xE001C018)) +> +> /* SPI (Serial Peripheral Interface) */ +> /* only for lpc210x*/ +> #define SPI_SPCR (*((volatile unsigned char *) 0xE0020000)) +> #define SPI_SPSR (*((volatile unsigned char *) 0xE0020004)) +> #define SPI_SPDR (*((volatile unsigned char *) 0xE0020008)) +> #define SPI_SPCCR (*((volatile unsigned char *) 0xE002000C)) +> #define SPI_SPINT (*((volatile unsigned char *) 0xE002001C)) +> +> #ifdef CONFIG_ARCH_LPC22xx +> #define S0PCR (*((volatile unsigned char *) 0xE0020000)) /* no in lpc210x*/ +> #define S0PSR (*((volatile unsigned char *) 0xE0020004)) /* no in lpc210x*/ +> #define S0PDR (*((volatile unsigned char *) 0xE0020008)) /* no in lpc210x*/ +> #define S0PCCR (*((volatile unsigned char *) 0xE002000C)) /* no in lpc210x*/ +> #define S0PINT (*((volatile unsigned char *) 0xE002001C)) /* no in lpc210x*/ +> +> #define S1PCR (*((volatile unsigned char *) 0xE0030000)) /* no in lpc210x*/ +> #define S1PSR (*((volatile unsigned char *) 0xE0030004)) /* no in lpc210x*/ +> #define S1PDR (*((volatile unsigned char *) 0xE0030008)) /* no in lpc210x*/ +> #define S1PCCR (*((volatile unsigned char *) 0xE003000C)) /* no in lpc210x*/ +> #define S1PINT (*((volatile unsigned char *) 0xE003001C)) /* no in lpc210x*/ +> #endif +> /* CAN CONTROLLERS AND ACCEPTANCE FILTER */ +> #define CAN1MOD (*((volatile unsigned long *) 0xE0044000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1CMR (*((volatile unsigned long *) 0xE0044004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1GSR (*((volatile unsigned long *) 0xE0044008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1ICR (*((volatile unsigned long *) 0xE004400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1IER (*((volatile unsigned long *) 0xE0044010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1BTR (*((volatile unsigned long *) 0xE0044014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1EWL (*((volatile unsigned long *) 0xE004401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1SR (*((volatile unsigned long *) 0xE0044020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1RFS (*((volatile unsigned long *) 0xE0044024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1RDA (*((volatile unsigned long *) 0xE0044028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1RDB (*((volatile unsigned long *) 0xE004402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TFI1 (*((volatile unsigned long *) 0xE0044030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TID1 (*((volatile unsigned long *) 0xE0044034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDA1 (*((volatile unsigned long *) 0xE0044038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDB1 (*((volatile unsigned long *) 0xE004403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TFI2 (*((volatile unsigned long *) 0xE0044040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TID2 (*((volatile unsigned long *) 0xE0044044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDA2 (*((volatile unsigned long *) 0xE0044048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDB2 (*((volatile unsigned long *) 0xE004404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TFI3 (*((volatile unsigned long *) 0xE0044050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TID3 (*((volatile unsigned long *) 0xE0044054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDA3 (*((volatile unsigned long *) 0xE0044058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN1TDB3 (*((volatile unsigned long *) 0xE004405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #define CAN2MOD (*((volatile unsigned long *) 0xE0048000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2CMR (*((volatile unsigned long *) 0xE0048004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2GSR (*((volatile unsigned long *) 0xE0048008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2ICR (*((volatile unsigned long *) 0xE004800C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2IER (*((volatile unsigned long *) 0xE0048010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2BTR (*((volatile unsigned long *) 0xE0048014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2EWL (*((volatile unsigned long *) 0xE004801C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2SR (*((volatile unsigned long *) 0xE0048020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2RFS (*((volatile unsigned long *) 0xE0048024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2RDA (*((volatile unsigned long *) 0xE0048028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2RDB (*((volatile unsigned long *) 0xE004802C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TFI1 (*((volatile unsigned long *) 0xE0048030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TID1 (*((volatile unsigned long *) 0xE0048034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDA1 (*((volatile unsigned long *) 0xE0048038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDB1 (*((volatile unsigned long *) 0xE004803C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TFI2 (*((volatile unsigned long *) 0xE0048040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TID2 (*((volatile unsigned long *) 0xE0048044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDA2 (*((volatile unsigned long *) 0xE0048048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDB2 (*((volatile unsigned long *) 0xE004804C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TFI3 (*((volatile unsigned long *) 0xE0048050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TID3 (*((volatile unsigned long *) 0xE0048054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDA3 (*((volatile unsigned long *) 0xE0048058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN2TDB3 (*((volatile unsigned long *) 0xE004805C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #define CAN3MOD (*((volatile unsigned long *) 0xE004C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3CMR (*((volatile unsigned long *) 0xE004C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3GSR (*((volatile unsigned long *) 0xE004C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3ICR (*((volatile unsigned long *) 0xE004C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3IER (*((volatile unsigned long *) 0xE004C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3BTR (*((volatile unsigned long *) 0xE004C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3EWL (*((volatile unsigned long *) 0xE004C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3SR (*((volatile unsigned long *) 0xE004C020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3RFS (*((volatile unsigned long *) 0xE004C024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3RDA (*((volatile unsigned long *) 0xE004C028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3RDB (*((volatile unsigned long *) 0xE004C02C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TFI1 (*((volatile unsigned long *) 0xE004C030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TID1 (*((volatile unsigned long *) 0xE004C034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDA1 (*((volatile unsigned long *) 0xE004C038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDB1 (*((volatile unsigned long *) 0xE004C03C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TFI2 (*((volatile unsigned long *) 0xE004C040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TID2 (*((volatile unsigned long *) 0xE004C044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDA2 (*((volatile unsigned long *) 0xE004C048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDB2 (*((volatile unsigned long *) 0xE004C04C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TFI3 (*((volatile unsigned long *) 0xE004C050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TID3 (*((volatile unsigned long *) 0xE004C054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDA3 (*((volatile unsigned long *) 0xE004C058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN3TDB3 (*((volatile unsigned long *) 0xE004C05C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #define CAN4MOD (*((volatile unsigned long *) 0xE0050000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4CMR (*((volatile unsigned long *) 0xE0050004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4GSR (*((volatile unsigned long *) 0xE0050008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4ICR (*((volatile unsigned long *) 0xE005000C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4IER (*((volatile unsigned long *) 0xE0050010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4BTR (*((volatile unsigned long *) 0xE0050014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4EWL (*((volatile unsigned long *) 0xE005001C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4SR (*((volatile unsigned long *) 0xE0050020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4RFS (*((volatile unsigned long *) 0xE0050024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4RDA (*((volatile unsigned long *) 0xE0050028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4RDB (*((volatile unsigned long *) 0xE005002C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TFI1 (*((volatile unsigned long *) 0xE0050030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TID1 (*((volatile unsigned long *) 0xE0050034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDA1 (*((volatile unsigned long *) 0xE0050038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDB1 (*((volatile unsigned long *) 0xE005003C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TFI2 (*((volatile unsigned long *) 0xE0050040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TID2 (*((volatile unsigned long *) 0xE0050044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDA2 (*((volatile unsigned long *) 0xE0050048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDB2 (*((volatile unsigned long *) 0xE005004C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TFI3 (*((volatile unsigned long *) 0xE0050050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TID3 (*((volatile unsigned long *) 0xE0050054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDA3 (*((volatile unsigned long *) 0xE0050058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN4TDB3 (*((volatile unsigned long *) 0xE005005C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #define CAN5MOD (*((volatile unsigned long *) 0xE0054000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5CMR (*((volatile unsigned long *) 0xE0054004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5GSR (*((volatile unsigned long *) 0xE0054008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5ICR (*((volatile unsigned long *) 0xE005400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5IER (*((volatile unsigned long *) 0xE0054010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5BTR (*((volatile unsigned long *) 0xE0054014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5EWL (*((volatile unsigned long *) 0xE005401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5SR (*((volatile unsigned long *) 0xE0054020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5RFS (*((volatile unsigned long *) 0xE0054024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5RDA (*((volatile unsigned long *) 0xE0054028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5RDB (*((volatile unsigned long *) 0xE005402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TFI1 (*((volatile unsigned long *) 0xE0054030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TID1 (*((volatile unsigned long *) 0xE0054034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDA1 (*((volatile unsigned long *) 0xE0054038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDB1 (*((volatile unsigned long *) 0xE005403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TFI2 (*((volatile unsigned long *) 0xE0054040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TID2 (*((volatile unsigned long *) 0xE0054044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDA2 (*((volatile unsigned long *) 0xE0054048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDB2 (*((volatile unsigned long *) 0xE005404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TFI3 (*((volatile unsigned long *) 0xE0054050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TID3 (*((volatile unsigned long *) 0xE0054054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDA3 (*((volatile unsigned long *) 0xE0054058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CAN5TDB3 (*((volatile unsigned long *) 0xE005405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #ifdef CONFIG_ARCH_LPC22xx +> #define CAN6MOD (*((volatile unsigned long *) 0xE0058000)) /* lpc2292\lpc2294 only */ +> #define CAN6CMR (*((volatile unsigned long *) 0xE0058004)) /* lpc2292\lpc2294 only */ +> #define CAN6GSR (*((volatile unsigned long *) 0xE0058008)) /* lpc2292\lpc2294 only */ +> #define CAN6ICR (*((volatile unsigned long *) 0xE005800C)) /* lpc2292\lpc2294 only */ +> #define CAN6IER (*((volatile unsigned long *) 0xE0058010)) /* lpc2292\lpc2294 only */ +> #define CAN6BTR (*((volatile unsigned long *) 0xE0058014)) /* lpc2292\lpc2294 only */ +> #define CAN6EWL (*((volatile unsigned long *) 0xE005801C)) /* lpc2292\lpc2294 only */ +> #define CAN6SR (*((volatile unsigned long *) 0xE0058020)) /* lpc2292\lpc2294 only */ +> #define CAN6RFS (*((volatile unsigned long *) 0xE0058024)) /* lpc2292\lpc2294 only */ +> #define CAN6RDA (*((volatile unsigned long *) 0xE0058028)) /* lpc2292\lpc2294 only */ +> #define CAN6RDB (*((volatile unsigned long *) 0xE005802C)) /* lpc2292\lpc2294 only */ +> #define CAN6TFI1 (*((volatile unsigned long *) 0xE0058030)) /* lpc2292\lpc2294 only */ +> #define CAN6TID1 (*((volatile unsigned long *) 0xE0058034)) /* lpc2292\lpc2294 only */ +> #define CAN6TDA1 (*((volatile unsigned long *) 0xE0058038)) /* lpc2292\lpc2294 only */ +> #define CAN6TDB1 (*((volatile unsigned long *) 0xE005803C)) /* lpc2292\lpc2294 only */ +> #define CAN6TFI2 (*((volatile unsigned long *) 0xE0058040)) /* lpc2292\lpc2294 only */ +> #define CAN6TID2 (*((volatile unsigned long *) 0xE0058044)) /* lpc2292\lpc2294 only */ +> #define CAN6TDA2 (*((volatile unsigned long *) 0xE0058048)) /* lpc2292\lpc2294 only */ +> #define CAN6TDB2 (*((volatile unsigned long *) 0xE005804C)) /* lpc2292\lpc2294 only */ +> #define CAN6TFI3 (*((volatile unsigned long *) 0xE0058050)) /* lpc2292\lpc2294 only */ +> #define CAN6TID3 (*((volatile unsigned long *) 0xE0058054)) /* lpc2292\lpc2294 only */ +> #define CAN6TDA3 (*((volatile unsigned long *) 0xE0058058)) /* lpc2292\lpc2294 only */ +> #define CAN6TDB3 (*((volatile unsigned long *) 0xE005805C)) /* lpc2292\lpc2294 only */ +> #endif +> +> #define CANTxSR (*((volatile unsigned long *) 0xE0040000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANRxSR (*((volatile unsigned long *) 0xE0040004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANMSR (*((volatile unsigned long *) 0xE0040008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> +> #define CANAFMR (*((volatile unsigned long *) 0xE003C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANSFF_sa (*((volatile unsigned long *) 0xE003C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANSFF_GRP_sa (*((volatile unsigned long *) 0xE003C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANEFF_sa (*((volatile unsigned long *) 0xE003C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANEFF_GRP_sa (*((volatile unsigned long *) 0xE003C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANENDofTable (*((volatile unsigned long *) 0xE003C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANLUTerrAd (*((volatile unsigned long *) 0xE003C018)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> #define CANLUTerr (*((volatile unsigned long *) 0xE003C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +> /* CAN Acceptance Filter RAM */ +> #define CANAFRAM (*((volatile unsigned long *) 0xE0038000)) +> +> +> /* Timer 0 */ +> #define T0IR (*((volatile unsigned long *) 0xE0004000)) +> #define T0TCR (*((volatile unsigned long *) 0xE0004004)) +> #define T0TC (*((volatile unsigned long *) 0xE0004008)) +> #define T0PR (*((volatile unsigned long *) 0xE000400C)) +> #define T0PC (*((volatile unsigned long *) 0xE0004010)) +> #define T0MCR (*((volatile unsigned long *) 0xE0004014)) +> #define T0MR0 (*((volatile unsigned long *) 0xE0004018)) +> #define T0MR1 (*((volatile unsigned long *) 0xE000401C)) +> #define T0MR2 (*((volatile unsigned long *) 0xE0004020)) +> #define T0MR3 (*((volatile unsigned long *) 0xE0004024)) +> #define T0CCR (*((volatile unsigned long *) 0xE0004028)) +> #define T0CR0 (*((volatile unsigned long *) 0xE000402C)) +> #define T0CR1 (*((volatile unsigned long *) 0xE0004030)) +> #define T0CR2 (*((volatile unsigned long *) 0xE0004034)) +> #define T0CR3 (*((volatile unsigned long *) 0xE0004038)) +> #define T0EMR (*((volatile unsigned long *) 0xE000403C)) +> +> /* Timer 1 */ +> #define T1IR (*((volatile unsigned long *) 0xE0008000)) +> #define T1TCR (*((volatile unsigned long *) 0xE0008004)) +> #define T1TC (*((volatile unsigned long *) 0xE0008008)) +> #define T1PR (*((volatile unsigned long *) 0xE000800C)) +> #define T1PC (*((volatile unsigned long *) 0xE0008010)) +> #define T1MCR (*((volatile unsigned long *) 0xE0008014)) +> #define T1MR0 (*((volatile unsigned long *) 0xE0008018)) +> #define T1MR1 (*((volatile unsigned long *) 0xE000801C)) +> #define T1MR2 (*((volatile unsigned long *) 0xE0008020)) +> #define T1MR3 (*((volatile unsigned long *) 0xE0008024)) +> #define T1CCR (*((volatile unsigned long *) 0xE0008028)) +> #define T1CR0 (*((volatile unsigned long *) 0xE000802C)) +> #define T1CR1 (*((volatile unsigned long *) 0xE0008030)) +> #define T1CR2 (*((volatile unsigned long *) 0xE0008034)) +> #define T1CR3 (*((volatile unsigned long *) 0xE0008038)) +> #define T1EMR (*((volatile unsigned long *) 0xE000803C)) +> +> /* Pulse Width Modulator (PWM) */ +> #define PWMIR (*((volatile unsigned long *) 0xE0014000)) +> #define PWMTCR (*((volatile unsigned long *) 0xE0014004)) +> #define PWMTC (*((volatile unsigned long *) 0xE0014008)) +> #define PWMPR (*((volatile unsigned long *) 0xE001400C)) +> #define PWMPC (*((volatile unsigned long *) 0xE0014010)) +> #define PWMMCR (*((volatile unsigned long *) 0xE0014014)) +> #define PWMMR0 (*((volatile unsigned long *) 0xE0014018)) +> #define PWMMR1 (*((volatile unsigned long *) 0xE001401C)) +> #define PWMMR2 (*((volatile unsigned long *) 0xE0014020)) +> #define PWMMR3 (*((volatile unsigned long *) 0xE0014024)) +> #define PWMMR4 (*((volatile unsigned long *) 0xE0014040)) +> #define PWMMR5 (*((volatile unsigned long *) 0xE0014044)) +> #define PWMMR6 (*((volatile unsigned long *) 0xE0014048)) +> #define PWMPCR (*((volatile unsigned long *) 0xE001404C)) +> #define PWMLER (*((volatile unsigned long *) 0xE0014050)) +> +> /* A/D CONVERTER */ +> #ifndef CONFIG_ARCH_LPC2104 +> #define ADCR (*((volatile unsigned long *) 0xE0034000)) /* no in lpc210x*/ +> #define ADDR (*((volatile unsigned long *) 0xE0034004)) /* no in lpc210x*/ +> #endif +> +> /* Real Time Clock */ +> #define ILR (*((volatile unsigned char *) 0xE0024000)) +> #define CTC (*((volatile unsigned short*) 0xE0024004)) +> #define CCR (*((volatile unsigned char *) 0xE0024008)) +> #define CIIR (*((volatile unsigned char *) 0xE002400C)) +> #define AMR (*((volatile unsigned char *) 0xE0024010)) +> #define CTIME0 (*((volatile unsigned long *) 0xE0024014)) +> #define CTIME1 (*((volatile unsigned long *) 0xE0024018)) +> #define CTIME2 (*((volatile unsigned long *) 0xE002401C)) +> #define SEC (*((volatile unsigned char *) 0xE0024020)) +> #define MIN (*((volatile unsigned char *) 0xE0024024)) +> #define HOUR (*((volatile unsigned char *) 0xE0024028)) +> #define DOM (*((volatile unsigned char *) 0xE002402C)) +> #define DOW (*((volatile unsigned char *) 0xE0024030)) +> #define DOY (*((volatile unsigned short*) 0xE0024034)) +> #define MONTH (*((volatile unsigned char *) 0xE0024038)) +> #define YEAR (*((volatile unsigned short*) 0xE002403C)) +> #define ALSEC (*((volatile unsigned char *) 0xE0024060)) +> #define ALMIN (*((volatile unsigned char *) 0xE0024064)) +> #define ALHOUR (*((volatile unsigned char *) 0xE0024068)) +> #define ALDOM (*((volatile unsigned char *) 0xE002406C)) +> #define ALDOW (*((volatile unsigned char *) 0xE0024070)) +> #define ALDOY (*((volatile unsigned short*) 0xE0024074)) +> #define ALMON (*((volatile unsigned char *) 0xE0024078)) +> #define ALYEAR (*((volatile unsigned short*) 0xE002407C)) +> #define PREINT (*((volatile unsigned short*) 0xE0024080)) +> #define PREFRAC (*((volatile unsigned short*) 0xE0024084)) +> +> /* Watchdog */ +> #define WDMOD (*((volatile unsigned char *) 0xE0000000)) +> #define WDTC (*((volatile unsigned long *) 0xE0000004)) +> #define WDFEED (*((volatile unsigned char *) 0xE0000008)) +> #define WDTV (*((volatile unsigned long *) 0xE000000C)) +> +> /* +> Register define for constant +> */ +> #define REG_U0RBR 0xE000C000 +> #define REG_U1RBR 0xE0010000 +> +> /* PLL */ +> #define REG_PLLCON 0xE01FC080 +> #define REG_PLLCFG 0xE01FC084 +> #define REG_PLLSTAT 0xE01FC088 +> #define REG_PLLFEED 0xE01FC08C +> +> /* Power Control */ +> +> #define REG_PCON 0xE01FC0C0 +> #define REG_PCOMP 0xE01FC0C4 +> #define REG_PINSEL0 0xE002C000 +> #define REG_MEMMAP 0xE01FC040 +> #define REG_PLLSTAT 0xE01FC088 +> #define REG_VPBDIV 0xE01FC100 +> +> +> +> #define LPC22xx_Fcclk CONFIG_ARM_CLK /* system clk frequecy,<=60Mhz, defined in system configuration */ +> #define LPC22xx_Fcco LPC22xx_Fcclk * 4 +> #define LPC22xx_Fpclk (LPC22xx_Fcclk /4) *1 /*VPB clk frequency,1,1/2,1/4 times of Fcclk */ +> +> #endif +> /********************************************************************************************************* +> ** End Of File +> ********************************************************************************************************/ diff --git a/include/asm-arm/arch-lpc22xx/lpc22xx.h b/include/asm-arm/arch-lpc22xx/lpc22xx.h new file mode 100644 index 00000000..30bc0a3d --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/lpc22xx.h @@ -0,0 +1,469 @@ + +#ifndef __ASM_ARCH_LPC22xx_H +#define __ASM_ARCH_LPC22xx_H + +/* EXTERNAL MEMORY CONTROLLER (EMC) */ +#define BCFG0 (*((volatile unsigned int *) 0xFFE00000)) /* lpc22xx only */ +#define BCFG1 (*((volatile unsigned int *) 0xFFE00004)) /* lpc22xx only */ +#define BCFG2 (*((volatile unsigned int *) 0xFFE00008)) /* lpc22xx only */ +#define BCFG3 (*((volatile unsigned int *) 0xFFE0000C)) /* lpc22xx only */ + +/* External Interrupts */ +#define EXTINT (*((volatile unsigned char *) 0xE01FC140)) +#define EXTWAKE (*((volatile unsigned char *) 0xE01FC144)) +#ifdef CONFIG_ARCH_LPC22xx +#define EXTMODE (*((volatile unsigned char *) 0xE01FC148)) /* no in lpc210x*/ +#define EXTPOLAR (*((volatile unsigned char *) 0xE01FC14C)) /* no in lpc210x*/ +#endif + +/* SMemory mapping control. */ +#define MEMMAP (*((volatile unsigned char *) 0xE01FC040)) + +/* Phase Locked Loop (PLL) */ +#define PLLCON (*((volatile unsigned char *) 0xE01FC080)) +#define PLLCFG (*((volatile unsigned char *) 0xE01FC084)) +#define PLLSTAT (*((volatile unsigned short*) 0xE01FC088)) +#define PLLFEED (*((volatile unsigned char *) 0xE01FC08C)) + +/* Power Control */ +#define PCON (*((volatile unsigned char *) 0xE01FC0C0)) +#define PCONP (*((volatile unsigned long *) 0xE01FC0C4)) + +/* VPB Divider */ +#define VPBDIV (*((volatile unsigned char *) 0xE01FC100)) + +/* Memory Accelerator Module (MAM) */ +#define MAMCR (*((volatile unsigned char *) 0xE01FC000)) +#define MAMTIM (*((volatile unsigned char *) 0xE01FC004)) + +/* Vectored Interrupt Controller (VIC) */ +#define VICIRQStatus (*((volatile unsigned long *) 0xFFFFF000)) +#define VICFIQStatus (*((volatile unsigned long *) 0xFFFFF004)) +#define VICRawIntr (*((volatile unsigned long *) 0xFFFFF008)) +#define VICIntSelect (*((volatile unsigned long *) 0xFFFFF00C)) +#define VICIntEnable (*((volatile unsigned long *) 0xFFFFF010)) +#define VICIntEnClr (*((volatile unsigned long *) 0xFFFFF014)) +#define VICSoftInt (*((volatile unsigned long *) 0xFFFFF018)) +#define VICSoftIntClear (*((volatile unsigned long *) 0xFFFFF01C)) +#define VICProtection (*((volatile unsigned long *) 0xFFFFF020)) +#define VICVectAddr (*((volatile unsigned long *) 0xFFFFF030)) +#define VICDefVectAddr (*((volatile unsigned long *) 0xFFFFF034)) +#define VICVectAddr0 (*((volatile unsigned long *) 0xFFFFF100)) +#define VICVectAddr1 (*((volatile unsigned long *) 0xFFFFF104)) +#define VICVectAddr2 (*((volatile unsigned long *) 0xFFFFF108)) +#define VICVectAddr3 (*((volatile unsigned long *) 0xFFFFF10C)) +#define VICVectAddr4 (*((volatile unsigned long *) 0xFFFFF110)) +#define VICVectAddr5 (*((volatile unsigned long *) 0xFFFFF114)) +#define VICVectAddr6 (*((volatile unsigned long *) 0xFFFFF118)) +#define VICVectAddr7 (*((volatile unsigned long *) 0xFFFFF11C)) +#define VICVectAddr8 (*((volatile unsigned long *) 0xFFFFF120)) +#define VICVectAddr9 (*((volatile unsigned long *) 0xFFFFF124)) +#define VICVectAddr10 (*((volatile unsigned long *) 0xFFFFF128)) +#define VICVectAddr11 (*((volatile unsigned long *) 0xFFFFF12C)) +#define VICVectAddr12 (*((volatile unsigned long *) 0xFFFFF130)) +#define VICVectAddr13 (*((volatile unsigned long *) 0xFFFFF134)) +#define VICVectAddr14 (*((volatile unsigned long *) 0xFFFFF138)) +#define VICVectAddr15 (*((volatile unsigned long *) 0xFFFFF13C)) +#define VICVectCntl0 (*((volatile unsigned long *) 0xFFFFF200)) +#define VICVectCntl1 (*((volatile unsigned long *) 0xFFFFF204)) +#define VICVectCntl2 (*((volatile unsigned long *) 0xFFFFF208)) +#define VICVectCntl3 (*((volatile unsigned long *) 0xFFFFF20C)) +#define VICVectCntl4 (*((volatile unsigned long *) 0xFFFFF210)) +#define VICVectCntl5 (*((volatile unsigned long *) 0xFFFFF214)) +#define VICVectCntl6 (*((volatile unsigned long *) 0xFFFFF218)) +#define VICVectCntl7 (*((volatile unsigned long *) 0xFFFFF21C)) +#define VICVectCntl8 (*((volatile unsigned long *) 0xFFFFF220)) +#define VICVectCntl9 (*((volatile unsigned long *) 0xFFFFF224)) +#define VICVectCntl10 (*((volatile unsigned long *) 0xFFFFF228)) +#define VICVectCntl11 (*((volatile unsigned long *) 0xFFFFF22C)) +#define VICVectCntl12 (*((volatile unsigned long *) 0xFFFFF230)) +#define VICVectCntl13 (*((volatile unsigned long *) 0xFFFFF234)) +#define VICVectCntl14 (*((volatile unsigned long *) 0xFFFFF238)) +#define VICVectCntl15 (*((volatile unsigned long *) 0xFFFFF23C)) + +/* Pin Connect Block */ +#define PINSEL0 (*((volatile unsigned long *) 0xE002C000)) +#define PINSEL1 (*((volatile unsigned long *) 0xE002C004)) +#ifdef CONFIG_ARCH_LPC22xx +#define PINSEL2 (*((volatile unsigned long *) 0xE002C014)) /* no in lpc210x*/ +#endif + +/* General Purpose Input/Output (GPIO) */ +#ifndef CONFIG_ARCH_LPC22xx + +#define IOPIN (*((volatile unsigned long *) 0xE0028000)) /* lpc210x only */ +#define IOSET (*((volatile unsigned long *) 0xE0028004)) /* lpc210x only */ +#define IODIR (*((volatile unsigned long *) 0xE0028008)) /* lpc210x only */ +#define IOCLR (*((volatile unsigned long *) 0xE002800C)) /* lpc210x only */ + +#endif + +#ifdef CONFIG_ARCH_LPC22xx +#define IO0PIN (*((volatile unsigned long *) 0xE0028000)) /* no in lpc210x*/ +#define IO0SET (*((volatile unsigned long *) 0xE0028004)) /* no in lpc210x*/ +#define IO0DIR (*((volatile unsigned long *) 0xE0028008)) /* no in lpc210x*/ +#define IO0CLR (*((volatile unsigned long *) 0xE002800C)) /* no in lpc210x*/ + +#define IO1PIN (*((volatile unsigned long *) 0xE0028010)) /* no in lpc210x*/ +#define IO1SET (*((volatile unsigned long *) 0xE0028014)) /* no in lpc210x*/ +#define IO1DIR (*((volatile unsigned long *) 0xE0028018)) /* no in lpc210x*/ +#define IO1CLR (*((volatile unsigned long *) 0xE002801C)) /* no in lpc210x*/ +#endif + +#ifdef CONFIG_ARCH_LPC22xx + +#define IO2PIN (*((volatile unsigned long *) 0xE0028020)) /* lpc22xx only */ +#define IO2SET (*((volatile unsigned long *) 0xE0028024)) /* lpc22xx only */ +#define IO2DIR (*((volatile unsigned long *) 0xE0028028)) /* lpc22xx only */ +#define IO2CLR (*((volatile unsigned long *) 0xE002802C)) /* lpc22xx only */ + +#define IO3PIN (*((volatile unsigned long *) 0xE0028030)) /* lpc22xx only */ +#define IO3SET (*((volatile unsigned long *) 0xE0028034)) /* lpc22xx only */ +#define IO3DIR (*((volatile unsigned long *) 0xE0028038)) /* lpc22xx only */ +#define IO3CLR (*((volatile unsigned long *) 0xE002803C)) /* lpc22xx only */ + +#endif + +/* Universal Asynchronous Receiver Transmitter 0 (UART0) */ +#define U0RBR (*((volatile unsigned char *) 0xE000C000)) +#define U0THR (*((volatile unsigned char *) 0xE000C000)) +#define U0IER (*((volatile unsigned char *) 0xE000C004)) +#define U0IIR (*((volatile unsigned char *) 0xE000C008)) +#define U0FCR (*((volatile unsigned char *) 0xE000C008)) +#define U0LCR (*((volatile unsigned char *) 0xE000C00C)) +#define U0LSR (*((volatile unsigned char *) 0xE000C014)) +#define U0SCR (*((volatile unsigned char *) 0xE000C01C)) +#define U0DLL (*((volatile unsigned char *) 0xE000C000)) +#define U0DLM (*((volatile unsigned char *) 0xE000C004)) + +/* Universal Asynchronous Receiver Transmitter 1 (UART1) */ +#define U1RBR (*((volatile unsigned char *) 0xE0010000)) +#define U1THR (*((volatile unsigned char *) 0xE0010000)) +#define U1IER (*((volatile unsigned char *) 0xE0010004)) +#define U1IIR (*((volatile unsigned char *) 0xE0010008)) +#define U1FCR (*((volatile unsigned char *) 0xE0010008)) +#define U1LCR (*((volatile unsigned char *) 0xE001000C)) +#define U1MCR (*((volatile unsigned char *) 0xE0010010)) +#define U1LSR (*((volatile unsigned char *) 0xE0010014)) +#define U1MSR (*((volatile unsigned char *) 0xE0010018)) +#define U1SCR (*((volatile unsigned char *) 0xE001001C)) +#define U1DLL (*((volatile unsigned char *) 0xE0010000)) +#define U1DLM (*((volatile unsigned char *) 0xE0010004)) + +/* I2C (8/16 bit data bus) */ +#define I2CONSET (*((volatile unsigned char *) 0xE001C000)) +#define I2STAT (*((volatile unsigned char *) 0xE001C004)) +#define I2DAT (*((volatile unsigned char *) 0xE001C008)) +#define I2ADR (*((volatile unsigned char *) 0xE001C00C)) +#define I2SCLH (*((volatile unsigned short *) 0xE001C010)) +#define I2SCLL (*((volatile unsigned short *) 0xE001C014)) +#define I2CONCLR (*((volatile unsigned char *) 0xE001C018)) + +/* SPI (Serial Peripheral Interface) */ + /* only for lpc210x*/ +#define SPI_SPCR (*((volatile unsigned char *) 0xE0020000)) +#define SPI_SPSR (*((volatile unsigned char *) 0xE0020004)) +#define SPI_SPDR (*((volatile unsigned char *) 0xE0020008)) +#define SPI_SPCCR (*((volatile unsigned char *) 0xE002000C)) +#define SPI_SPINT (*((volatile unsigned char *) 0xE002001C)) + +#ifdef CONFIG_ARCH_LPC22xx +#define S0PCR (*((volatile unsigned char *) 0xE0020000)) /* no in lpc210x*/ +#define S0PSR (*((volatile unsigned char *) 0xE0020004)) /* no in lpc210x*/ +#define S0PDR (*((volatile unsigned char *) 0xE0020008)) /* no in lpc210x*/ +#define S0PCCR (*((volatile unsigned char *) 0xE002000C)) /* no in lpc210x*/ +#define S0PINT (*((volatile unsigned char *) 0xE002001C)) /* no in lpc210x*/ + +#define S1PCR (*((volatile unsigned char *) 0xE0030000)) /* no in lpc210x*/ +#define S1PSR (*((volatile unsigned char *) 0xE0030004)) /* no in lpc210x*/ +#define S1PDR (*((volatile unsigned char *) 0xE0030008)) /* no in lpc210x*/ +#define S1PCCR (*((volatile unsigned char *) 0xE003000C)) /* no in lpc210x*/ +#define S1PINT (*((volatile unsigned char *) 0xE003001C)) /* no in lpc210x*/ +#endif +/* CAN CONTROLLERS AND ACCEPTANCE FILTER */ +#define CAN1MOD (*((volatile unsigned long *) 0xE0044000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1CMR (*((volatile unsigned long *) 0xE0044004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1GSR (*((volatile unsigned long *) 0xE0044008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1ICR (*((volatile unsigned long *) 0xE004400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1IER (*((volatile unsigned long *) 0xE0044010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1BTR (*((volatile unsigned long *) 0xE0044014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1EWL (*((volatile unsigned long *) 0xE004401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1SR (*((volatile unsigned long *) 0xE0044020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1RFS (*((volatile unsigned long *) 0xE0044024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1RDA (*((volatile unsigned long *) 0xE0044028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1RDB (*((volatile unsigned long *) 0xE004402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TFI1 (*((volatile unsigned long *) 0xE0044030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TID1 (*((volatile unsigned long *) 0xE0044034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDA1 (*((volatile unsigned long *) 0xE0044038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDB1 (*((volatile unsigned long *) 0xE004403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TFI2 (*((volatile unsigned long *) 0xE0044040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TID2 (*((volatile unsigned long *) 0xE0044044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDA2 (*((volatile unsigned long *) 0xE0044048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDB2 (*((volatile unsigned long *) 0xE004404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TFI3 (*((volatile unsigned long *) 0xE0044050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TID3 (*((volatile unsigned long *) 0xE0044054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDA3 (*((volatile unsigned long *) 0xE0044058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN1TDB3 (*((volatile unsigned long *) 0xE004405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#define CAN2MOD (*((volatile unsigned long *) 0xE0048000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2CMR (*((volatile unsigned long *) 0xE0048004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2GSR (*((volatile unsigned long *) 0xE0048008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2ICR (*((volatile unsigned long *) 0xE004800C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2IER (*((volatile unsigned long *) 0xE0048010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2BTR (*((volatile unsigned long *) 0xE0048014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2EWL (*((volatile unsigned long *) 0xE004801C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2SR (*((volatile unsigned long *) 0xE0048020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2RFS (*((volatile unsigned long *) 0xE0048024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2RDA (*((volatile unsigned long *) 0xE0048028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2RDB (*((volatile unsigned long *) 0xE004802C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TFI1 (*((volatile unsigned long *) 0xE0048030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TID1 (*((volatile unsigned long *) 0xE0048034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDA1 (*((volatile unsigned long *) 0xE0048038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDB1 (*((volatile unsigned long *) 0xE004803C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TFI2 (*((volatile unsigned long *) 0xE0048040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TID2 (*((volatile unsigned long *) 0xE0048044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDA2 (*((volatile unsigned long *) 0xE0048048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDB2 (*((volatile unsigned long *) 0xE004804C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TFI3 (*((volatile unsigned long *) 0xE0048050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TID3 (*((volatile unsigned long *) 0xE0048054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDA3 (*((volatile unsigned long *) 0xE0048058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN2TDB3 (*((volatile unsigned long *) 0xE004805C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#define CAN3MOD (*((volatile unsigned long *) 0xE004C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3CMR (*((volatile unsigned long *) 0xE004C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3GSR (*((volatile unsigned long *) 0xE004C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3ICR (*((volatile unsigned long *) 0xE004C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3IER (*((volatile unsigned long *) 0xE004C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3BTR (*((volatile unsigned long *) 0xE004C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3EWL (*((volatile unsigned long *) 0xE004C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3SR (*((volatile unsigned long *) 0xE004C020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3RFS (*((volatile unsigned long *) 0xE004C024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3RDA (*((volatile unsigned long *) 0xE004C028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3RDB (*((volatile unsigned long *) 0xE004C02C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TFI1 (*((volatile unsigned long *) 0xE004C030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TID1 (*((volatile unsigned long *) 0xE004C034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDA1 (*((volatile unsigned long *) 0xE004C038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDB1 (*((volatile unsigned long *) 0xE004C03C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TFI2 (*((volatile unsigned long *) 0xE004C040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TID2 (*((volatile unsigned long *) 0xE004C044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDA2 (*((volatile unsigned long *) 0xE004C048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDB2 (*((volatile unsigned long *) 0xE004C04C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TFI3 (*((volatile unsigned long *) 0xE004C050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TID3 (*((volatile unsigned long *) 0xE004C054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDA3 (*((volatile unsigned long *) 0xE004C058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN3TDB3 (*((volatile unsigned long *) 0xE004C05C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#define CAN4MOD (*((volatile unsigned long *) 0xE0050000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4CMR (*((volatile unsigned long *) 0xE0050004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4GSR (*((volatile unsigned long *) 0xE0050008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4ICR (*((volatile unsigned long *) 0xE005000C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4IER (*((volatile unsigned long *) 0xE0050010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4BTR (*((volatile unsigned long *) 0xE0050014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4EWL (*((volatile unsigned long *) 0xE005001C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4SR (*((volatile unsigned long *) 0xE0050020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4RFS (*((volatile unsigned long *) 0xE0050024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4RDA (*((volatile unsigned long *) 0xE0050028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4RDB (*((volatile unsigned long *) 0xE005002C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TFI1 (*((volatile unsigned long *) 0xE0050030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TID1 (*((volatile unsigned long *) 0xE0050034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDA1 (*((volatile unsigned long *) 0xE0050038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDB1 (*((volatile unsigned long *) 0xE005003C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TFI2 (*((volatile unsigned long *) 0xE0050040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TID2 (*((volatile unsigned long *) 0xE0050044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDA2 (*((volatile unsigned long *) 0xE0050048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDB2 (*((volatile unsigned long *) 0xE005004C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TFI3 (*((volatile unsigned long *) 0xE0050050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TID3 (*((volatile unsigned long *) 0xE0050054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDA3 (*((volatile unsigned long *) 0xE0050058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN4TDB3 (*((volatile unsigned long *) 0xE005005C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#define CAN5MOD (*((volatile unsigned long *) 0xE0054000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5CMR (*((volatile unsigned long *) 0xE0054004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5GSR (*((volatile unsigned long *) 0xE0054008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5ICR (*((volatile unsigned long *) 0xE005400C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5IER (*((volatile unsigned long *) 0xE0054010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5BTR (*((volatile unsigned long *) 0xE0054014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5EWL (*((volatile unsigned long *) 0xE005401C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5SR (*((volatile unsigned long *) 0xE0054020)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5RFS (*((volatile unsigned long *) 0xE0054024)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5RDA (*((volatile unsigned long *) 0xE0054028)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5RDB (*((volatile unsigned long *) 0xE005402C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TFI1 (*((volatile unsigned long *) 0xE0054030)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TID1 (*((volatile unsigned long *) 0xE0054034)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDA1 (*((volatile unsigned long *) 0xE0054038)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDB1 (*((volatile unsigned long *) 0xE005403C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TFI2 (*((volatile unsigned long *) 0xE0054040)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TID2 (*((volatile unsigned long *) 0xE0054044)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDA2 (*((volatile unsigned long *) 0xE0054048)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDB2 (*((volatile unsigned long *) 0xE005404C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TFI3 (*((volatile unsigned long *) 0xE0054050)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TID3 (*((volatile unsigned long *) 0xE0054054)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDA3 (*((volatile unsigned long *) 0xE0054058)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CAN5TDB3 (*((volatile unsigned long *) 0xE005405C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#ifdef CONFIG_ARCH_LPC22xx +#define CAN6MOD (*((volatile unsigned long *) 0xE0058000)) /* lpc2292\lpc2294 only */ +#define CAN6CMR (*((volatile unsigned long *) 0xE0058004)) /* lpc2292\lpc2294 only */ +#define CAN6GSR (*((volatile unsigned long *) 0xE0058008)) /* lpc2292\lpc2294 only */ +#define CAN6ICR (*((volatile unsigned long *) 0xE005800C)) /* lpc2292\lpc2294 only */ +#define CAN6IER (*((volatile unsigned long *) 0xE0058010)) /* lpc2292\lpc2294 only */ +#define CAN6BTR (*((volatile unsigned long *) 0xE0058014)) /* lpc2292\lpc2294 only */ +#define CAN6EWL (*((volatile unsigned long *) 0xE005801C)) /* lpc2292\lpc2294 only */ +#define CAN6SR (*((volatile unsigned long *) 0xE0058020)) /* lpc2292\lpc2294 only */ +#define CAN6RFS (*((volatile unsigned long *) 0xE0058024)) /* lpc2292\lpc2294 only */ +#define CAN6RDA (*((volatile unsigned long *) 0xE0058028)) /* lpc2292\lpc2294 only */ +#define CAN6RDB (*((volatile unsigned long *) 0xE005802C)) /* lpc2292\lpc2294 only */ +#define CAN6TFI1 (*((volatile unsigned long *) 0xE0058030)) /* lpc2292\lpc2294 only */ +#define CAN6TID1 (*((volatile unsigned long *) 0xE0058034)) /* lpc2292\lpc2294 only */ +#define CAN6TDA1 (*((volatile unsigned long *) 0xE0058038)) /* lpc2292\lpc2294 only */ +#define CAN6TDB1 (*((volatile unsigned long *) 0xE005803C)) /* lpc2292\lpc2294 only */ +#define CAN6TFI2 (*((volatile unsigned long *) 0xE0058040)) /* lpc2292\lpc2294 only */ +#define CAN6TID2 (*((volatile unsigned long *) 0xE0058044)) /* lpc2292\lpc2294 only */ +#define CAN6TDA2 (*((volatile unsigned long *) 0xE0058048)) /* lpc2292\lpc2294 only */ +#define CAN6TDB2 (*((volatile unsigned long *) 0xE005804C)) /* lpc2292\lpc2294 only */ +#define CAN6TFI3 (*((volatile unsigned long *) 0xE0058050)) /* lpc2292\lpc2294 only */ +#define CAN6TID3 (*((volatile unsigned long *) 0xE0058054)) /* lpc2292\lpc2294 only */ +#define CAN6TDA3 (*((volatile unsigned long *) 0xE0058058)) /* lpc2292\lpc2294 only */ +#define CAN6TDB3 (*((volatile unsigned long *) 0xE005805C)) /* lpc2292\lpc2294 only */ +#endif + +#define CANTxSR (*((volatile unsigned long *) 0xE0040000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANRxSR (*((volatile unsigned long *) 0xE0040004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANMSR (*((volatile unsigned long *) 0xE0040008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ + +#define CANAFMR (*((volatile unsigned long *) 0xE003C000)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANSFF_sa (*((volatile unsigned long *) 0xE003C004)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANSFF_GRP_sa (*((volatile unsigned long *) 0xE003C008)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANEFF_sa (*((volatile unsigned long *) 0xE003C00C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANEFF_GRP_sa (*((volatile unsigned long *) 0xE003C010)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANENDofTable (*((volatile unsigned long *) 0xE003C014)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANLUTerrAd (*((volatile unsigned long *) 0xE003C018)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +#define CANLUTerr (*((volatile unsigned long *) 0xE003C01C)) /* lpc2119\lpc2129\lpc2292\lpc2294 only */ +/* CAN Acceptance Filter RAM */ +#define CANAFRAM (*((volatile unsigned long *) 0xE0038000)) + + +/* Timer 0 */ +#define T0IR (*((volatile unsigned long *) 0xE0004000)) +#define T0TCR (*((volatile unsigned long *) 0xE0004004)) +#define T0TC (*((volatile unsigned long *) 0xE0004008)) +#define T0PR (*((volatile unsigned long *) 0xE000400C)) +#define T0PC (*((volatile unsigned long *) 0xE0004010)) +#define T0MCR (*((volatile unsigned long *) 0xE0004014)) +#define T0MR0 (*((volatile unsigned long *) 0xE0004018)) +#define T0MR1 (*((volatile unsigned long *) 0xE000401C)) +#define T0MR2 (*((volatile unsigned long *) 0xE0004020)) +#define T0MR3 (*((volatile unsigned long *) 0xE0004024)) +#define T0CCR (*((volatile unsigned long *) 0xE0004028)) +#define T0CR0 (*((volatile unsigned long *) 0xE000402C)) +#define T0CR1 (*((volatile unsigned long *) 0xE0004030)) +#define T0CR2 (*((volatile unsigned long *) 0xE0004034)) +#define T0CR3 (*((volatile unsigned long *) 0xE0004038)) +#define T0EMR (*((volatile unsigned long *) 0xE000403C)) + +/* Timer 1 */ +#define T1IR (*((volatile unsigned long *) 0xE0008000)) +#define T1TCR (*((volatile unsigned long *) 0xE0008004)) +#define T1TC (*((volatile unsigned long *) 0xE0008008)) +#define T1PR (*((volatile unsigned long *) 0xE000800C)) +#define T1PC (*((volatile unsigned long *) 0xE0008010)) +#define T1MCR (*((volatile unsigned long *) 0xE0008014)) +#define T1MR0 (*((volatile unsigned long *) 0xE0008018)) +#define T1MR1 (*((volatile unsigned long *) 0xE000801C)) +#define T1MR2 (*((volatile unsigned long *) 0xE0008020)) +#define T1MR3 (*((volatile unsigned long *) 0xE0008024)) +#define T1CCR (*((volatile unsigned long *) 0xE0008028)) +#define T1CR0 (*((volatile unsigned long *) 0xE000802C)) +#define T1CR1 (*((volatile unsigned long *) 0xE0008030)) +#define T1CR2 (*((volatile unsigned long *) 0xE0008034)) +#define T1CR3 (*((volatile unsigned long *) 0xE0008038)) +#define T1EMR (*((volatile unsigned long *) 0xE000803C)) + +/* Pulse Width Modulator (PWM) */ +#define PWMIR (*((volatile unsigned long *) 0xE0014000)) +#define PWMTCR (*((volatile unsigned long *) 0xE0014004)) +#define PWMTC (*((volatile unsigned long *) 0xE0014008)) +#define PWMPR (*((volatile unsigned long *) 0xE001400C)) +#define PWMPC (*((volatile unsigned long *) 0xE0014010)) +#define PWMMCR (*((volatile unsigned long *) 0xE0014014)) +#define PWMMR0 (*((volatile unsigned long *) 0xE0014018)) +#define PWMMR1 (*((volatile unsigned long *) 0xE001401C)) +#define PWMMR2 (*((volatile unsigned long *) 0xE0014020)) +#define PWMMR3 (*((volatile unsigned long *) 0xE0014024)) +#define PWMMR4 (*((volatile unsigned long *) 0xE0014040)) +#define PWMMR5 (*((volatile unsigned long *) 0xE0014044)) +#define PWMMR6 (*((volatile unsigned long *) 0xE0014048)) +#define PWMPCR (*((volatile unsigned long *) 0xE001404C)) +#define PWMLER (*((volatile unsigned long *) 0xE0014050)) + +/* A/D CONVERTER */ +#ifndef CONFIG_ARCH_LPC2104 +#define ADCR (*((volatile unsigned long *) 0xE0034000)) /* no in lpc210x*/ +#define ADDR (*((volatile unsigned long *) 0xE0034004)) /* no in lpc210x*/ +#endif + +/* Real Time Clock */ +#define ILR (*((volatile unsigned char *) 0xE0024000)) +#define CTC (*((volatile unsigned short*) 0xE0024004)) +#define CCR (*((volatile unsigned char *) 0xE0024008)) +#define CIIR (*((volatile unsigned char *) 0xE002400C)) +#define AMR (*((volatile unsigned char *) 0xE0024010)) +#define CTIME0 (*((volatile unsigned long *) 0xE0024014)) +#define CTIME1 (*((volatile unsigned long *) 0xE0024018)) +#define CTIME2 (*((volatile unsigned long *) 0xE002401C)) +#define SEC (*((volatile unsigned char *) 0xE0024020)) +#define MIN (*((volatile unsigned char *) 0xE0024024)) +#define HOUR (*((volatile unsigned char *) 0xE0024028)) +#define DOM (*((volatile unsigned char *) 0xE002402C)) +#define DOW (*((volatile unsigned char *) 0xE0024030)) +#define DOY (*((volatile unsigned short*) 0xE0024034)) +#define MONTH (*((volatile unsigned char *) 0xE0024038)) +#define YEAR (*((volatile unsigned short*) 0xE002403C)) +#define ALSEC (*((volatile unsigned char *) 0xE0024060)) +#define ALMIN (*((volatile unsigned char *) 0xE0024064)) +#define ALHOUR (*((volatile unsigned char *) 0xE0024068)) +#define ALDOM (*((volatile unsigned char *) 0xE002406C)) +#define ALDOW (*((volatile unsigned char *) 0xE0024070)) +#define ALDOY (*((volatile unsigned short*) 0xE0024074)) +#define ALMON (*((volatile unsigned char *) 0xE0024078)) +#define ALYEAR (*((volatile unsigned short*) 0xE002407C)) +#define PREINT (*((volatile unsigned short*) 0xE0024080)) +#define PREFRAC (*((volatile unsigned short*) 0xE0024084)) + +/* Watchdog */ +#define WDMOD (*((volatile unsigned char *) 0xE0000000)) +#define WDTC (*((volatile unsigned long *) 0xE0000004)) +#define WDFEED (*((volatile unsigned char *) 0xE0000008)) +#define WDTV (*((volatile unsigned long *) 0xE000000C)) + +/* + Register define for constant +*/ +#define REG_U0RBR 0xE000C000 +#define REG_U1RBR 0xE0010000 + +/* PLL */ +#define REG_PLLCON 0xE01FC080 +#define REG_PLLCFG 0xE01FC084 +#define REG_PLLSTAT 0xE01FC088 +#define REG_PLLFEED 0xE01FC08C + +/* Power Control */ + +#define REG_PCON 0xE01FC0C0 +#define REG_PCOMP 0xE01FC0C4 +#define REG_PINSEL0 0xE002C000 +#define REG_MEMMAP 0xE01FC040 +#define REG_PLLSTAT 0xE01FC088 +#define REG_VPBDIV 0xE01FC100 + + + +#define LPC22xx_Fcclk CONFIG_ARM_CLK /* system clk frequecy,<=60Mhz, defined in system configuration */ +#define LPC22xx_Fcco LPC22xx_Fcclk * 4 +#define LPC22xx_Fpclk (LPC22xx_Fcclk /4) *1 /*VPB clk frequency,1,1/2,1/4 times of Fcclk */ + +#endif +/********************************************************************************************************* +** End Of File +********************************************************************************************************/ diff --git a/include/asm-arm/arch-lpc22xx/memory.h b/include/asm-arm/arch-lpc22xx/memory.h new file mode 100644 index 00000000..d6722da7 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/memory.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/memory.h + * + * Copyright (C) 2004 Philips semiconductors + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x81a00000) +#define TASK_SIZE_26 TASK_SIZE +#define TASK_UNMAPPED_BASE (0x0) + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-lpc22xx/param.h b/include/asm-arm/arch-lpc22xx/param.h new file mode 100644 index 00000000..cf2482d6 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/param.h @@ -0,0 +1,8 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ +/*#ifndef HZ +#define HZ 100 +#endif*/ +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-lpc22xx/serial.h b/include/asm-arm/arch-lpc22xx/serial.h new file mode 100644 index 00000000..e5060a5d --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/serial.h @@ -0,0 +1,43 @@ +/* + * include/asm-arm/arch-lpc2210/serial.h + * + * Copyright (C) 2004 Philips Semiconductors + */ + +#ifndef __ASM_ARCH_SERIAL_H__ +#define __ASM_ARCH_SERIAL_H__ + +#include + +#define BASE_BAUD (LPC22xx_Fpclk / 16) +#define UART0_BASE 0xE000C000 +#define UART1_BASE 0xE0010000 + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define RS_TABLE_SIZE 2 + +/* + * Rather empty table... + * Hardwired serial ports should be defined here. + * PCMCIA will fill it dynamically. + */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, UART0_BASE, 6, STD_COM_FLAGS, \ + .iomem_reg_shift = 2, \ + .iomem_base = UART0_BASE, \ + .io_type = UPIO_MEM}, \ + { 1, BASE_BAUD, UART1_BASE, 7, STD_COM_FLAGS, \ + .iomem_reg_shift = 2, \ + .iomem_base = UART1_BASE, \ + .io_type = UPIO_MEM} + +#define EXTRA_SERIAL_PORT_DEFNS + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DEFNS \ + EXTRA_SERIAL_PORT_DEFNS + +#endif /* __ASM_ARCH_SERIAL_H__ */ diff --git a/include/asm-arm/arch-lpc22xx/system.h b/include/asm-arm/arch-lpc22xx/system.h new file mode 100644 index 00000000..dd83bc2e --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/system.h @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/system.h + * + * Copyright (C) 2004 Philips Semiconductors + * + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0);/*will jump to cpu_arm7_reset in proc-arm67.S,since lpc22xx have no cache,we must modify the code*/ +} + +#endif diff --git a/include/asm-arm/arch-lpc22xx/time.h b/include/asm-arm/arch-lpc22xx/time.h new file mode 100644 index 00000000..46fdd2b0 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/time.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/time.h + * + * Copyright (C) 2004 Philips Semiconductors + */ + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ + +#include +#include +#include +#include + +#define CLOCKS_PER_USEC (LPC22xx_Fpclk/1000000) + +/* set timer to generate interrupt every 10ms */ +/* MR0/(LPC22xx_Fpclk/(PR0+1)) = 10/1000 = 0.01s */ +#define MR0_INIT_VALUE 10 +#define PRESCALE_COUNTER_INIT_VALUE (LPC22xx_Fpclk/1000) - 1 + + +#endif /*__ASM_ARCH_TIME_H__*/ diff --git a/include/asm-arm/arch-lpc22xx/timex.h b/include/asm-arm/arch-lpc22xx/timex.h new file mode 100644 index 00000000..badfa358 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/timex.h @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/timex.h + * + * Copyright (C) 2004 Philips Semiconductors ELECTRONICS + * + * 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 + */ + +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE (CONFIG_ARM_CLK) + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-lpc22xx/vmalloc.h b/include/asm-arm/arch-lpc22xx/vmalloc.h new file mode 100644 index 00000000..f06b9827 --- /dev/null +++ b/include/asm-arm/arch-lpc22xx/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-arm/arch-lpc22xx/vmalloc.h + * + * Copyright (C) 2000 Russell King. + * modified by Philips Semiconductors + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_LPC22xx_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_LPC22xx_SDRAM_SIZE) diff --git a/include/asm-arm/arch-moxart/cpe_int.h b/include/asm-arm/arch-moxart/cpe_int.h new file mode 100644 index 00000000..8ea23ea2 --- /dev/null +++ b/include/asm-arm/arch-moxart/cpe_int.h @@ -0,0 +1,8 @@ +/* + cpe_int.h must include in driver + maintened by ivan wang 2004/8/18 11:25 +*/ +#ifndef _CPE_INT_H +#define _CPE_INT_H +extern void cpe_int_set_irq(unsigned int irq, int mode, int level); +#endif diff --git a/include/asm-arm/arch-moxart/cpe_time.h b/include/asm-arm/arch-moxart/cpe_time.h new file mode 100644 index 00000000..be44888a --- /dev/null +++ b/include/asm-arm/arch-moxart/cpe_time.h @@ -0,0 +1,86 @@ +#ifndef _CPE_TIME_H_ +#define _CPE_TIME_H_ +//#include +//#include + +#define TIMER1_COUNT 0x0 +#define TIMER1_LOAD 0x4 +#define TIMER1_MATCH1 0x8 +#define TIMER1_MATCH2 0xC +#define TIMER2_COUNT 0x10 +#define TIMER2_LOAD 0x14 +#define TIMER2_MATCH1 0x18 +#define TIMER2_MATCH2 0x1C +#define TIMER3_COUNT 0x20 +#define TIMER3_LOAD 0x24 +#define TIMER3_MATCH1 0x28 +#define TIMER3_MATCH2 0x2C +#define TIMER_CR 0x30 +#define TIMER_INTR_STATE 0x34 +#define TIMER_INTR_MASK 0x38 + +typedef struct +{ + unsigned int Tm1En:1; // Timer1 enable bit + unsigned int Tm1Clock:1; // Timer1 clock source (0: PCLK, 1: EXT1CLK) + unsigned int Tm1OfEn:1; // Timer1 over flow interrupt enable bit + unsigned int Tm2En:1; + unsigned int Tm2Clock:1; + unsigned int Tm2OfEn:1; + unsigned int Tm3En:1; + unsigned int Tm3Clock:1; + unsigned int Tm3OfEn:1; + unsigned int Reserved; +} cpe_time_ctrl_t; + +typedef struct +{ + unsigned int TimerValue; + unsigned int TimerLoad; + unsigned int TimerMatch1; + unsigned int TimerMatch2; +} cpe_time_reg_t; + +extern cpe_time_reg_t *TimerBase[]; + +#if 0 // mask by Victor Yu. 01-31-2008 +extern unsigned int cpe_timer_enable(unsigned int timer); +extern unsigned int cpe_timer_disable(unsigned int timer); +extern void cpe_timer_set_counter(unsigned int timer, unsigned int value); +extern void cpe_timer_set_reload(unsigned int timer, unsigned int value); +extern unsigned int cpe_timer_get_counter(unsigned int timer); +#endif + +extern struct irqaction timer_irq; +extern unsigned long cpe_gettimeoffset(void); + +#if 0 // mask by Victor Yu. 11-17-2005 +static inline void cpe_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); +} + +static inline void setup_timer(void) +{ +#ifdef TIMER_INC_MODE + cpe_timer_set_reload(1, 0xffffffff - APB_CLK/HZ); + cpe_timer_set_counter(1, 0xffffffff - APB_CLK/HZ); +#else + cpe_timer_set_reload(1, APB_CLK/HZ); + cpe_timer_set_counter(1, APB_CLK/HZ); +#endif + + if(!cpe_timer_enable(1)) + { + panic("can not enable timer\n"); + } + + printk("IRQ timer at interrupt number 0x%x clock %d\r\n",IRQ_TIMER1,APB_CLK); + cpe_int_set_irq(IRQ_TIMER1, EDGE,L_ACTIVE); + timer_irq.handler = cpe_timer_interrupt; + timer_irq.flags = SA_INTERRUPT; //ivan added + setup_arm_irq(IRQ_TIMER1, &timer_irq); +} +#endif + +#endif // _CPE_TIME_H diff --git a/include/asm-arm/arch-moxart/dma.h b/include/asm-arm/arch-moxart/dma.h new file mode 100644 index 00000000..d608c07d --- /dev/null +++ b/include/asm-arm/arch-moxart/dma.h @@ -0,0 +1,173 @@ + +/* + * This is Moxa CPU DMA (include APB & AHB) define file. + * Copyright (C) 2005 Moxa Group All Rights Reserved. + * + * History: + * Date Author Comment + * 12-01-2005 Victor Yu. Create it. + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff +#define MAX_DMA_CHANNELS 0 + +#define APB_DMA_MAX_CHANNEL 4 +#define AHB_DMA_MAX_CHANNEL 8 +#define TOTAL_DMA_MAX_CHANNEL (APB_DMA_MAX_CHANNEL+AHB_DMA_MAX_CHANNEL) + +// following define for APB DMA register struct +union _command { + unsigned int ul; +#define APB_DMA_ENABLE (1<<0) +#define APB_DMA_FIN_INT_STS (1<<1) +#define APB_DMA_FIN_INT_EN (1<<2) +#define APB_DMA_BURST_MODE (1<<3) +#define APB_DMA_ERR_INT_STS (1<<4) +#define APB_DMA_ERR_INT_EN (1<<5) +#define APB_DMA_SOURCE_AHB (1<<6) +#define APB_DMA_SOURCE_APB 0 +#define APB_DMA_DEST_AHB (1<<7) +#define APB_DMA_DEST_APB 0 +#define APB_DMA_SOURCE_INC_0 0 +#define APB_DMA_SOURCE_INC_1_4 (1<<8) +#define APB_DMA_SOURCE_INC_2_8 (2<<8) +#define APB_DMA_SOURCE_INC_4_16 (3<<8) +#define APB_DMA_SOURCE_DEC_1_4 (5<<8) +#define APB_DMA_SOURCE_DEC_2_8 (6<<8) +#define APB_DMA_SOURCE_DEC_4_16 (7<<8) +#define APB_DMA_SOURCE_INC_MASK (7<<8) +#define APB_DMA_DEST_INC_0 0 +#define APB_DMA_DEST_INC_1_4 (1<<12) +#define APB_DMA_DEST_INC_2_8 (2<<12) +#define APB_DMA_DEST_INC_4_16 (3<<12) +#define APB_DMA_DEST_DEC_1_4 (5<<12) +#define APB_DMA_DEST_DEC_2_8 (6<<12) +#define APB_DMA_DEST_DEC_4_16 (7<<12) +#define APB_DMA_DEST_INC_MASK (7<<12) +#define APB_DMA_DEST_REQ_NO_MASK (15<<16) +#define APB_DMA_DATA_WIDTH_MASK (3<<20) +#define APB_DMA_DATA_WIDTH_4 0 +#define APB_DMA_DATA_WIDTH_2 (1<<20) +#define APB_DMA_DATA_WIDTH_1 (2<<20) +#define APB_DMA_SOURCE_REQ_NO_MASK (15<<24) + struct _bits { + unsigned int enable:1; // enable DMA +#define APB_DMAB_ENABLE 1 + unsigned int fin_int_sts:1; // finished interrupt status +#define APB_DMAB_FIN_INT_STS 1 + unsigned int fin_int_en:1; // finished interrupt enable +#define APB_DMAB_FIN_INT_EN 1 + unsigned int burst:1; // burst mode +#define APB_DMAB_BURST_MODE 1 + unsigned int err_int_sts:1; // error interrupt status +#define APB_DMAB_ERR_INT_STS 1 + unsigned int err_int_en:1; // error interrupt enable +#define APB_DMAB_ERR_INT_EN 1 + unsigned int source_sel:1; // 0:APB (device),1:AHB (RAM) +#define APB_DMAB_SOURCE_AHB 1 +#define APB_DMAB_SOURCE_APB 0 + unsigned int dest_sel:1; // 0:APB,1:AHB +#define APB_DMAB_DEST_AHB 1 +#define APB_DMAB_DEST_APB 0 + unsigned int source_inc:3; // 000:no increment + // 001:+1(busrt=0),+4(burst=1) + // 010:+2(burst=0),+8(burst=1) + // 011:+4(burst=0),+16(burst=1) + // 101:-1(burst=0),-4(burst=1) + // 110:-2(burst=0),-8(burst=1) + // 111:-4(burst=0),-16(burst=1) +#define APB_DMAB_SOURCE_INC_0 0 +#define APB_DMAB_SOURCE_INC_1_4 1 +#define APB_DMAB_SOURCE_INC_2_8 2 +#define APB_DMAB_SOURCE_INC_4_16 3 +#define APB_DMAB_SOURCE_DEC_1_4 5 +#define APB_DMAB_SOURCE_DEC_2_8 6 +#define APB_DMAB_SOURCE_DEC_4_16 7 +#define APB_DMAB_SOURCE_INC_MASK 7 + unsigned int reserved1:1; + unsigned int dest_inc:3; // 000:no increment + // 001:+1(busrt=0),+4(burst=1) + // 010:+2(burst=0),+8(burst=1) + // 011:+4(burst=0),+16(burst=1) + // 101:-1(burst=0),-4(burst=1) + // 110:-2 (burst=0),-8(burst=1) + // 111:-4(burst=0),-16(burst=1) +#define APB_DMAB_DEST_INC_0 0 +#define APB_DMAB_DEST_INC_1_4 1 +#define APB_DMAB_DEST_INC_2_8 2 +#define APB_DMAB_DEST_INC_4_16 3 +#define APB_DMAB_DEST_DEC_1_4 5 +#define APB_DMAB_DEST_DEC_2_8 6 +#define APB_DMAB_DEST_DEC_4_16 7 +#define APB_DMAB_DEST_INC_MASK 7 + unsigned int reserved2:1; + unsigned int dest_req_no:4; // request signal select of dest + // addr for DMA hwd handshake + // 0:no request/grant signal + // 1-15:request/grant signal +#define APB_DMAB_DEST_REQ_NO_MASK 15 + unsigned int data_width:2; // data width of transfer + // 00:word, 01:half, 10:byte +#define APB_DMAB_DATA_WIDTH_MASK 3 +#define APB_DMAB_DATA_WIDTH_4 0 +#define APB_DMAB_DATA_WIDTH_2 1 +#define APB_DMAB_DATA_WIDTH_1 2 + unsigned int reserved3:2; + unsigned int source_req_no:4;// request signal select of dest + // addr for DMA hwd handshake + // 0:no request/grant signal + // 1-15:request/grant signal +#define APB_DMAB_SOURCE_REQ_NO_MASK 15 + unsigned int reserved4:4; + } bits; +}; + +typedef struct _apb_dma_reg { + unsigned int source_addr; + unsigned int dest_addr; + unsigned int cycles; // is depended on burst mode +#define APB_DMA_CYCLES_MASK 0x00ffffff + union _command command; +} apb_dma_reg; + +#define APB_DMA_SPI_TX_REQ_NO 1 +#define APB_DMA_SPI_RX_REQ_NO 2 +#define APB_DMA_SD_REQ_NO 5 +#define APB_DMA_AC97_TX_REQ_NO 6 +#define APB_DMA_AC97_RX_REQ_NO 7 +#define APB_DMA_USB_DEVICE_REQ_NO 9 + +// following APB DMA private data struct define +typedef struct _apb_dma_priv { + apb_dma_reg *reg; + void (*irq_handler)(void *param); + void *irq_handler_param; + int used_flag; + int error_flag; + int req_no; +} apb_dma_priv; + +typedef struct _apb_dma_conf_param { + unsigned int source_addr; // need physical address + unsigned int dest_addr; // need physical address + unsigned int size; // total bytes number + int data_width; + int dest_inc; + int source_inc; + int dest_sel; // APB or AHB + int source_sel; // APB or AHB + int burst_mode; +} apb_dma_conf_param; + +// following APB DMA function call phototype define +extern apb_dma_priv *apb_dma_alloc(int req_no); +extern void apb_dma_release(apb_dma_priv *priv); +extern void apb_dma_set_irq(apb_dma_priv *priv, void (*func)(void *param), void *param); +extern void apb_dma_release_irq(apb_dma_priv *priv); +extern void apb_dma_conf(apb_dma_priv *priv, apb_dma_conf_param *param); +extern void apb_dma_enable(apb_dma_priv *priv); +extern void apb_dma_disable(apb_dma_priv *priv); + +#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-moxart/entry-macro.S b/include/asm-arm/arch-moxart/entry-macro.S new file mode 100644 index 00000000..a0dc5039 --- /dev/null +++ b/include/asm-arm/arch-moxart/entry-macro.S @@ -0,0 +1,42 @@ +/* + * + * jimmy_chen@moxa.com.tw + */ + +//#include +#include +#if defined(CONFIG_ARCH_MOXART) + .macro disable_fiq + .endm + + .macro get_fiqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(IO_ADDRESS(CPE_IC_BASE)+FIQ_STATUS_REG) + ldr \irqstat, [\base] + mov \irqnr, #32 +2001: + tst \irqstat, #1 + bne 2002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #64 + bcc 2001b +2002: + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(CPE_IC_BASE+IRQ_STATUS_REG) + ldr \irqstat, [\base] + mov \irqnr, #0 +2003: + tst \irqstat, #1 + bne 2004f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #32 + bcc 2003b +2004: + .endm + + .macro irq_prio_table + .endm +#endif diff --git a/include/asm-arm/arch-moxart/ftpci.h b/include/asm-arm/arch-moxart/ftpci.h new file mode 100644 index 00000000..f1d1b7a2 --- /dev/null +++ b/include/asm-arm/arch-moxart/ftpci.h @@ -0,0 +1,74 @@ +#ifndef ARCH_CPE_FTPCI_H +#define ARCH_CPE_FTPCI_H +#include +#include +// -------------------------------------------------------------------- +// AHB Control Register +// -------------------------------------------------------------------- +#define FTPCI_IOSIZE_REG 0x0 +#define FTPCI_PROT_REG 0x4 +#define FTPCI_CTRL_REG 0x8 +#define FTPCI_ERREN_REG 0xc +#define FTPCI_SOFTRST_REG 0x10 +#define FTPCI_EN64_REG 0x14 +#define FTPCI_ADDRH32_REG 0x18 +#define FTPCI_CFG_ADR_REG 0x28 +#define FTPCI_CFG_DATA_REG 0x2c + + + // -------------------------------------------------------------------- + // FTPCI_IOSIZE_REG ªº¤º®e + // -------------------------------------------------------------------- +#define FTPCI_BASE_IO_SIZE_1M 0x0 +#define FTPCI_BASE_IO_SIZE_2M 0x1 +#define FTPCI_BASE_IO_SIZE_4M 0x2 +#define FTPCI_BASE_IO_SIZE_8M 0x3 +#define FTPCI_BASE_IO_SIZE_16M 0x4 +#define FTPCI_BASE_IO_SIZE_32M 0x5 +#define FTPCI_BASE_IO_SIZE_64M 0x6 +#define FTPCI_BASE_IO_SIZE_128M 0x7 +#define FTPCI_BASE_IO_SIZE_256M 0x8 +#define FTPCI_BASE_IO_SIZE_512M 0x9 +#define FTPCI_BASE_IO_SIZE_1G 0xa +#define FTPCI_BASE_IO_SIZE_2G 0xb + + + +// -------------------------------------------------------------------- +// PCI Configuration Register +// -------------------------------------------------------------------- +#define PCI_INT_MASK 0x4e +#define PCI_MEM_BASE_SIZE1 0x50 +#define PCI_MEM_BASE_SIZE2 0x54 +#define PCI_MEM_BASE_SIZE3 0x58 + + + // -------------------------------------------------------------------- + // PCI_INT_MASK ªº¤º®e + // -------------------------------------------------------------------- +#define PCI_INTA_ENABLE (1U<<6) +#define PCI_INTB_ENABLE (1U<<7) +#define PCI_INTC_ENABLE (1U<<8) +#define PCI_INTD_ENABLE (1U<<9) + + + // -------------------------------------------------------------------- + // PCI_MEM_BASE_SIZE1... ªº¤º®e + // -------------------------------------------------------------------- +#define FTPCI_BASE_ADR_SIZE_1MB (0x0<<16) +#define FTPCI_BASE_ADR_SIZE_2MB (0x1<<16) +#define FTPCI_BASE_ADR_SIZE_4MB (0x2<<16) +#define FTPCI_BASE_ADR_SIZE_8MB (0x3<<16) +#define FTPCI_BASE_ADR_SIZE_16MB (0x4<<16) +#define FTPCI_BASE_ADR_SIZE_32MB (0x5<<16) +#define FTPCI_BASE_ADR_SIZE_64MB (0x6<<16) +#define FTPCI_BASE_ADR_SIZE_128MB (0x7<<16) +#define FTPCI_BASE_ADR_SIZE_256MB (0x8<<16) +#define FTPCI_BASE_ADR_SIZE_512MB (0x9<<16) +#define FTPCI_BASE_ADR_SIZE_1GB (0xa<<16) +#define FTPCI_BASE_ADR_SIZE_2GB (0xb<<16) + +void ftpci_clear_irq(unsigned int irq); +inline int ftpci_get_irq(void); +extern int ftpci_probed; +#endif diff --git a/include/asm-arm/arch-moxart/gpio.h b/include/asm-arm/arch-moxart/gpio.h new file mode 100644 index 00000000..b78b62a0 --- /dev/null +++ b/include/asm-arm/arch-moxart/gpio.h @@ -0,0 +1,38 @@ + +#ifndef _MOXACPU_GPIO_H +#define _MOXACPU_GPIO_H + +typedef struct _mcpu_gpio_reg_struct { + unsigned int data_out; + unsigned int data_in; + unsigned int pin_dir; // 1 for output, 0 for input + unsigned int reserved; + unsigned int data_set; + unsigned int data_clear; + unsigned int pin_pull_enable; + unsigned int pin_pull_type; + unsigned int int_enable; + unsigned int int_raw_state; + unsigned int int_masked_state; + unsigned int int_mask; + unsigned int int_clear; + unsigned int int_trigger; + unsigned int int_both; + unsigned int int_rise_neg; + unsigned int bounce_enable; + unsigned int bounce_pre_scale; +} mcpu_gpio_reg_t; + +#define MCPU_GPIO_INPUT 0 +#define MCPU_GPIO_OUTPUT 1 +#define MCPU_GPIO_HIGH 1 +#define MCPU_GPIO_LOW 0 + +extern void mcpu_gpio_inout(u32 gpio, int inout); +extern u32 mcpu_gpio_get_inout(u32 gpio); +extern void mcpu_gpio_set(u32 gpio, int highlow); +extern u32 mcpu_gpio_get(u32 gpio); +extern void mcpu_gpio_mp_set(u32 gpio); +extern void mcpu_gpio_mp_clear(u32 gpio); + +#endif // _MOXACPU_GPIO_H diff --git a/include/asm-arm/arch-moxart/hardware.h b/include/asm-arm/arch-moxart/hardware.h new file mode 100644 index 00000000..e55315fd --- /dev/null +++ b/include/asm-arm/arch-moxart/hardware.h @@ -0,0 +1,19 @@ +/* + hardware.h + maintened by ivan wang 2004/8/18 11:25 +*/ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/ +#define PCIBIOS_MIN_IO 0x6000 +/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/ +#define PCIBIOS_MIN_MEM 0x100000 + +#define pcibios_assign_all_busses() 1 +#endif + +#if defined(CONFIG_DRAM_BASE) && defined(CONFIG_DRAM_SIZE) + #define PA_SDRAM_BASE (CONFIG_DRAM_BASE) + #define MEM_SIZE (CONFIG_DRAM_SIZE) +#endif diff --git a/include/asm-arm/arch-moxart/io.h b/include/asm-arm/arch-moxart/io.h new file mode 100644 index 00000000..7bb61380 --- /dev/null +++ b/include/asm-arm/arch-moxart/io.h @@ -0,0 +1,16 @@ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff +#define __io(a) (a) +#define __mem_pci(a) ((unsigned long)(a)) + +#if 0 // mask by Victor Yu. 11-16-2005 +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#endif + +#define iomem_valid_addr(iomem,sz) (1) +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-moxart/irq.h b/include/asm-arm/arch-moxart/irq.h new file mode 100644 index 00000000..f675b9c1 --- /dev/null +++ b/include/asm-arm/arch-moxart/irq.h @@ -0,0 +1,88 @@ +/* asm/arch-cpe/irq.h */ + +#ifndef __ASM_ARCH_IRQ_H__ +#define __ASM_ARCH_IRQ_H__ + +#include +#include +#include +#ifdef CONFIG_PCI +#include +#endif // CONFIG_PCI + +#if 0 // mask by Victor Yu. 03-15-2007 +extern void cpe_mask_irq(unsigned int irq); +extern void cpe_unmask_irq(unsigned int irq); +extern void cpe_mask_ack_irq(unsigned int irq); +extern void cpe_clear_irq(unsigned int intNum); +extern void cpe_int_init(void); + +#if 1 // add by Victor Yu. 05-17-2005 +extern struct irqchip cpe_irq_chip; +#include +#endif + +static inline void irq_init_irq(void) +{ + unsigned long flags; + int irq; + + save_and_cli(flags); + cpe_int_init(); + restore_flags(flags); +#if 1 // add by Victor Yu. 03-15-2007 + cpe_irq_chip.ack = cpe_mask_ack_irq; + cpe_irq_chip.mask = cpe_mask_irq; + cpe_irq_chip.unmask = cpe_unmask_irq; +#endif + for (irq = 0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &cpe_irq_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } +} +#endif + +static inline int fixup_irq(int irq) +{ +#ifdef CONFIG_ARCH_CPE + unsigned int status; + unsigned int i; + + if( irq == IRQ_EXT_A321 ) { + status=*(volatile unsigned int *)(CPE_A321_IC_VA_BASE+IRQ_STATUS_REG); + if( status & (1<<(IRQ_A321_PCI-CPE_A321_IRQ_START)) ) { //pci irq +#ifdef CONFIG_PCI + switch ( ftpci_get_irq() ) { + case 0: return VIRQ_PCI_A; + case 1: return VIRQ_PCI_B; + case 2: return VIRQ_PCI_C; + case 3: return VIRQ_PCI_D; + } +#endif // CONFIG_PCI + for( i=0; i<32 ;i++ ) { + if ( status & (1< +//#include +//#include +//#include +//#include +//#include + +/* +extern void moxa_mask_irq(unsigned int irq); +extern void moxa_unmask_irq(unsigned int irq); +extern void moxa_mask_ack_irq(unsigned int irq); +extern void moxa_clear_irq(unsigned int intNum); +*/ +// +//static inline void irq_init_irq(void) +//{ +// unsigned long flags; +// int irq; +// +// save_flags_cli(flags); +// cpe_int_init(); +// restore_flags(flags); +// +// for (irq = 0; irq < NR_IRQS; irq++) +// { +// irq_desc[irq].valid = 1; +// irq_desc[irq].probe_ok = 1; +// irq_desc[irq].mask_ack = cpe_mask_ack_irq; +// irq_desc[irq].mask = cpe_mask_irq; +// irq_desc[irq].unmask = cpe_unmask_irq; +// } +//} +// +//static inline int fixup_irq(int irq) +//{ +//#ifdef CONFIG_A320C_PLATFORM +// unsigned int status; +// unsigned int i; +// if(irq==IRQ_EXT_A321) +// { +// status=*(volatile unsigned int *)(CPE_A321_IC_VA_BASE+IRQ_STATUS_REG); +// if(status&(1<<(IRQ_A321_PCI-CPE_A321_IRQ_START))) //pci irq +// { +//#ifdef CONFIG_PCI +// switch(ftpci_get_irq()) +// { +// case 0: return VIRQ_PCI_A; +// case 1: return VIRQ_PCI_B; +// case 2: return VIRQ_PCI_C; +// case 3: return VIRQ_PCI_D; +// } +//#endif +// } +// for(i=0;i<32;i++) +// if (status&(1< + */ +#ifndef __ASM_ARCH_IRQS_H__ +#define __ASM_ARCH_IRQS_H__ + +#endif /* __ASM_ARCH_IRQS_H__ */ diff --git a/include/asm-arm/arch-moxart/memory.h b/include/asm-arm/arch-moxart/memory.h new file mode 100644 index 00000000..cff00875 --- /dev/null +++ b/include/asm-arm/arch-moxart/memory.h @@ -0,0 +1,56 @@ + +/* + * linux/include/asm-armnommu/arch-p52/memory.h + * + * Copyright (c) 1999 Nicolas Pitre + * 2001 Mindspeed + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* #include */ + +#if 0 /* mask by Victor Yu. 11-17-2005 */ +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +#define DRAM_BASE 0x00000000 +#define DRAM_SIZE CONFIG_DRAM_SIZE +#define MEM_SIZE DRAM_SIZE + +#define PHYS_OFFSET (DRAM_BASE) +#define PAGE_OFFSET (0xc0000000UL) +#define PAGE_OFFSET (DRAM_BASE) +#define END_MEM (DRAM_BASE + DRAM_SIZE) +#define DMA_SIZE 0xffffffff +#endif + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE +#define PHYS_OFFSET CONFIG_DRAM_BASE +#define PAGE_OFFSET CONFIG_DRAM_BASE +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) +#define dma_to_virt(dev, addr) ((void *)__bus_to_virt(addr)) +#define virt_to_dma(dev, addr) ((dma_addr_t)__virt_to_bus((unsigned long)(addr))) +#define page_to_dma(dev, page) ((dma_addr_t)__virt_to_bus((unsigned long)page_address(page))) + +#if 0 /* mask by Victor Yu. */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) + +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) (x - PAGE_OFFSET) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) (x + PAGE_OFFSET) + +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) +#endif +#endif diff --git a/include/asm-arm/arch-moxart/moxa-uart.h b/include/asm-arm/arch-moxart/moxa-uart.h new file mode 100644 index 00000000..3c041d9e --- /dev/null +++ b/include/asm-arm/arch-moxart/moxa-uart.h @@ -0,0 +1,83 @@ +/* for MOXA CPU embedded UART */ +#define MOXA_EMBEDDED_UART_IRQ 31 +#define MOXA_EMBEDDED_UART_BASE_REG 0x98200000L +#define MOXA_EMBEDDED_UART_BASE_INT 0x982000C0L +#define MOXA_EMBEDDED_UART_BASE_MODE 0x982000E0L +/* +#define MOXA_EMBEDDED_UART_IRQ 31 +#define MOXA_EMBEDDED_UART_BASE_REG 0xB0900000L +#define MOXA_EMBEDDED_UART_BASE_INT 0xB09000C0L +#define MOXA_EMBEDDED_UART_BASE_MODE 0xB09000E0L +*/ + +#define MOXA_EMBEDDED_UART_CLK 14745600 +/* for register offset */ +#define MOXA_EMBEDDED_UART_TX (UART_TX*4) +#define MOXA_EMBEDDED_UART_RX (UART_RX*4) +#define MOXA_EMBEDDED_UART_LCR (UART_LCR*4) +#define MOXA_EMBEDDED_UART_FCR (UART_FCR*4) +#define MOXA_EMBEDDED_UART_IIR (UART_IIR*4) +#define MOXA_EMBEDDED_UART_IER (UART_IER*4) +#define MOXA_EMBEDDED_UART_MCR (UART_MCR*4) +#define MOXA_EMBEDDED_UART_LSR (UART_LSR*4) +#define MOXA_EMBEDDED_UART_MSR (UART_MSR*4) +#define MOXA_EMBEDDED_UART_DLL (UART_DLL*4) +#define MOXA_EMBEDDED_UART_DLM (UART_DLM*4) + +/* for register mask */ +#define MOXA_EMBEDDED_MASK_IIR 0x3E + +/* Enhance mode */ +/* good data mode enable*/ +#define MOXA_FCR_GDA_MODE_ENABLE 0x20 +/* only good data put into RxFIFO */ +#define MOXA_FCR_GDA_ONLY_ENABLE 0x10 +/* enable CTS interrupt */ +#define MOXA_IER_ECTSI 0x80 +/* eanble RTS interrupt */ +#define MOXA_IER_ERTSI 0x40 +/* enable Xon/Xoff interrupt */ +#define MOXA_IER_XINT 0x20 +/* enable GDA interrupt */ +#define MOXA_IER_EGDAI 0x10 + +#define MOXA_RECV_ISR (UART_IER_RDI | MOXA_IER_EGDAI) + +/* GDA interrupt pending */ +#define MOXA_IIR_GDA 0x1C +#define MOXA_IIR_RDA 0x04 +#define MOXA_IIR_RTO 0x0C +#define MOXA_IIR_LSR 0x06 + +/* recieved Xon/Xoff or specical interrupt pending */ +#define MOXA_IIR_XSC 0x10 + +/* RTS/CTS change state interrupt pending */ +#define MOXA_IIR_RTSCTS 0x20 +#define MOXA_IIR_MASK 0x3E +#define MOXA_MCR_XON_FLAG 0x40 +#define MOXA_MCR_XON_ANY 0x80 +#define MOXA_MCR_TX_XON 0x08 + + +/* software flow control on chip mask value */ +#define MOXA_EFR_SF_MASK 0x0F +/* send Xon1/Xoff1 */ +#define MOXA_EFR_SF_TX2 0x04 +/* send Xon1,Xon2/Xoff1,Xoff2 */ +#define MOXA_EFR_SF_TX12 0x0C +/* don't send Xon/Xoff */ +#define MOXA_EFR_SF_TX_NO 0x00 +/* Tx software flow control mask */ +#define MOXA_EFR_SF_TX_MASK 0x0C +/* don't receive Xon/Xoff */ +#define MOXA_EFR_SF_RX_NO 0x00 +/* receive Xon1/Xoff1 */ +#define MOXA_EFR_SF_RX1 0x02 +/* receive Xon2/Xoff2 */ +#define MOXA_EFR_SF_RX2 0x01 +/* receive Xon1,Xon2/Xoff1,Xoff2 */ +#define MOXA_EFR_SF_RX12 0x03 +/* Rx software flow control mask */ +#define MOXA_EFR_SF_RX_MASK 0x03 + diff --git a/include/asm-arm/arch-moxart/moxa.h b/include/asm-arm/arch-moxart/moxa.h new file mode 100644 index 00000000..dd183860 --- /dev/null +++ b/include/asm-arm/arch-moxart/moxa.h @@ -0,0 +1,188 @@ +/* + * History: + * Date Author Comment + * 11-17-2005 Victor Yu. Create it. + */ + +#ifndef _MOXACPU_H +#define _MOXACPU_H + +/***************************************************************** + IO Mapping +*****************************************************************/ +#define MEM_ADDRESS(x) (x) +#define IO_ADDRESS(x) (x) +#define PHY_ADDRESS(x) (x) + +/***************************************************************** + Clock Setting +*****************************************************************/ +#define AHB_CLK 48000000 +#define APB_CLK 48000000 + +/****************************************************************** + AHB/APB device register mapping + *****************************************************************/ +#define CPE_AHB_BASE 0x90100000 +#define CPE_SRAMC_BASE 0x90200000 +#define CPE_SDRAMC_BASE 0x90300000 +#define CPE_AHBDMA_BASE 0x90400000 +#define CPE_APBDMA_BASE 0x90500000 +#define CPE_PMU_BASE 0x98100000 +#define CPE_TIMER_BASE 0x98400000 +#define CPE_TIMER1_BASE 0x98400000 +#define CPE_TIMER2_BASE 0x98400010 +#define CPE_GPIO_BASE 0x98700000 +#define CPE_IC_BASE 0x98800000 +#define CPE_SD_BASE 0x98e00000 +#define CPE_PCI_BASE 0x90c00000 +#define CPE_PCI_MEM 0xa0000000 +#define CPE_FTMAC_BASE 0x90900000 +#define CPE_FTMAC2_BASE 0x92000000 //2nd MAC +#define CPE_USBDEV_BASE 0x90b00000 //USB device +#define CPE_UART_BASE 0x98200000 +#define CPE_UART1_BASE 0x98200000 +#define CPE_UART2_BASE 0x98200020 +#define CPE_UART3_BASE 0x98200040 +#define CPE_UART4_BASE 0x98200060 +#define CPE_UART5_BASE 0x98200080 +#define CPE_UART6_BASE 0x982000a0 +#define CPE_UART_INT_VEC_BASE 0x982000c0 +#define CPE_UART_MODE_BASE 0x982000e4 +#define CPE_SPI_BASE 0x98b00000 +#define CPE_USBHOST_BASE 0x90a00000 +#define CPE_AES_DES_BASE 0x90f00000 +#define CPE_AC97_BASE 0x99400000 +#define CPE_RTC_BASE 0x98600000 +#define CPE_WATCHDOG_BASE 0x98500000 +#define CPE_EBI_BASE 0x92300000 + +//virtual address +#define CPE_AHB_VA_BASE IO_ADDRESS(CPE_AHB_BASE) +#define CPE_SRAMC_VA_BASEi IO_ADDRESS(CPE_SRAMC_BASE) +#define CPE_SDRAMC_VA_BASE IO_ADDRESS(CPE_SDRAMC_BASE) +#define CPE_AHBDMA_VA_BASE IO_ADDRESS(CPE_AHBDMA_BASE) +#define CPE_APBDMA_VA_BASE IO_ADDRESS(CPE_APBDMA_BASE) +#define CPE_PMU_VA_BASE IO_ADDRESS(CPE_PMU_BASE) +#define CPE_TIMER_VA_BASE IO_ADDRESS(CPE_TIMER_BASE) +#define CPE_TIMER1_VA_BASE IO_ADDRESS(CPE_TIMER1_BASE) +#define CPE_TIMER2_VA_BASE IO_ADDRESS(CPE_TIMER2_BASE) +#define CPE_GPIO_VA_BASE IO_ADDRESS(CPE_GPIO_BASE) +#define CPE_IC_VA_BASE IO_ADDRESS(CPE_IC_BASE) +#define CPE_SD_VA_BASE IO_ADDRESS(CPE_SD_BASE) +#define CPE_PCI_VA_BASE IO_ADDRESS(CPE_PCI_BASE) +#define CPE_PCI_VA_MEM IO_ADDRESS(CPE_PCI_MEM) +#define CPE_FTMAC_VA_BASE IO_ADDRESS(CPE_FTMAC_BASE) +#define CPE_FTMAC2_VA_BASE IO_ADDRESS(CPE_FTMAC2_BASE) //2nd MAC +#define CPE_USBDEV_VA_BASE IO_ADDRESS(CPE_USBDEV_BASE) //USB device +#define CPE_UART_VA_BASE IO_ADDRESS(CPE_UART_BASE) +#define CPE_UART1_VA_BASE IO_ADDRESS(CPE_UART1_BASE) +#define CPE_UART2_VA_BASE IO_ADDRESS(CPE_UART2_BASE) +#define CPE_UART3_VA_BASE IO_ADDRESS(CPE_UART3_BASE) +#define CPE_UART4_VA_BASE IO_ADDRESS(CPE_UART4_BASE) +#define CPE_UART5_VA_BASE IO_ADDRESS(CPE_UART5_BASE) +#define CPE_UART6_VA_BASE IO_ADDRESS(CPE_UART6_BASE) +#define CPE_UART_INT_VEC_VA_BASE IO_ADDRESS(CPE_UART_INT_VEC_BASE) +#define CPE_UART_MODE_VA_BASE IO_ADDRESS(CPE_UART_MODE_BASE) +#define CPE_SPI_VA_BASE IO_ADDRESS(CPE_SPI_BASE) +#define CPE_USBHOST_VA_BASE IO_ADDRESS(CPE_USBHOST_BASE) +#define CPE_AES_DES_VA_BASE IO_ADDRESS(CPE_AES_DES_BASE) +#define CPE_AC97_VA_BASE IO_ADDRESS(CPE_AC97_BASE) +#define CPE_RTC_VA_BASE IO_ADDRESS(CPE_RTC_BASE) +#define CPE_WATCHDOG_VA_BASE IO_ADDRESS(CPE_WATCHDOG_BASE) +#define CPE_EBI_VA_BASE IO_ADDRESS(CPE_EBI_BASE) + +/***************************************************************** + IRQ +*****************************************************************/ +/* +interrupt: + 0-31 irq + 32-63 fiq + 64 - 67 Virtual IRQ (PCI) + 68 - 99 Virtual IRQ (reserved) + */ +#if 0 // mask by Victor Yu. 11-21-2005, to use default value 128 +#define NR_IRQS 100 +#endif +#define CPE_VIRQ_START 64 +#define CPE_NR_IRQS 32 +#define CPE_NR_FIQS 32 + +#define VIRQ_PCI_A (0+CPE_VIRQ_START) +#define VIRQ_PCI_B (1+CPE_VIRQ_START) +#define VIRQ_PCI_C (2+CPE_VIRQ_START) +#define VIRQ_PCI_D (3+CPE_VIRQ_START) + +//irq number +#define IRQ_GPIO 13 +#define IRQ_MAC 25 +#define IRQ_TIMER1 19 +#define IRQ_TIMER2 14 +#define IRQ_TIMER3 15 +#define IRQ_UART 31 +#define IRQ_AES_DES 29 +#define IRQ_USBHOST 28 +#define IRQ_MAC2 27 +#define IRQ_PCI 26 +#define IRQ_APBDMA 24 +#define IRQ_DMAC_ERR 23 +#define IRQ_DMAC_TC 22 +#define IRQ_DMAC 21 +#define IRQ_RTC_SECOND 18 +#define IRQ_RTC_ALARM 17 +#define IRQ_WATCHDOG 16 +#define IRQ_USBDEV_RESUME 12 +#define IRQ_USBDEV 11 +#define IRQ_PMU 8 +#define IRQ_AC97 6 +#define IRQ_SD 5 +#define IRQ_SPI 2 + +#define LEVEL 0 +#define EDGE 1 +#define H_ACTIVE 0 +#define L_ACTIVE 1 + +#define IRQ_SOURCE_REG 0 +#define IRQ_MASK_REG 0x04 +#define IRQ_CLEAR_REG 0x08 +#define IRQ_MODE_REG 0x0c +#define IRQ_LEVEL_REG 0x10 +#define IRQ_STATUS_REG 0x14 + +#define FIQ_SOURCE_REG 0x20 +#define FIQ_MASK_REG 0x24 +#define FIQ_CLEAR_REG 0x28 +#define FIQ_MODE_REG 0x2c +#define FIQ_LEVEL_REG 0x30 +#define FIQ_STATUS_REG 0x34 + +/***************************************************************** + Flash +*****************************************************************/ +#if 0 // mask by Victor Yu. 11-17-2005 +#define CPE_FLASH_BASE 0x80400000 +#define CPE_FLASH_SZ 0x02000000 +#define CPE_FLASH_VA_BASE MEM_ADDRESS(CPE_FLASH_BASE) +#endif + +/***************************************************************** + PCI +*****************************************************************/ +#define PCI_IO_VA_BASE (CPE_PCI_VA_BASE+SZ_4K) +#define PCI_IO_VA_SIZE (SZ_1M-SZ_4K) +#define PCI_IO_VA_END (CPE_PCI_VA_BASE+SZ_1M) +#define PCI_MEM_BASE CPE_PCI_MEM +#define PCI_MEM_SIZE SZ_1M +#define PCI_MEM_END (CPE_PCI_MEM+SZ_1M) + +#define PCI_BRIDGE_DEVID 0x4321 +#define PCI_BRIDGE_VENID 0x159b + +/***************************************************************** + PMU +*****************************************************************/ +#define PMU_SSP_DMA_CHANNEL 0x2 + +#endif // _MOXACPU_H diff --git a/include/asm-arm/arch-moxart/param.h b/include/asm-arm/arch-moxart/param.h new file mode 100644 index 00000000..7b8884ec --- /dev/null +++ b/include/asm-arm/arch-moxart/param.h @@ -0,0 +1,4 @@ +#ifndef _PARAM_H_ +#define _PARAM_H_ +#define HZ 100 +#endif diff --git a/include/asm-arm/arch-moxart/processor.h b/include/asm-arm/arch-moxart/processor.h new file mode 100644 index 00000000..c7b84609 --- /dev/null +++ b/include/asm-arm/arch-moxart/processor.h @@ -0,0 +1,17 @@ +#ifdef not_complete_yet +/* + * uclinux/include/asm-armnommu/arch-atmel/mmu.h + * + */ +#ifndef __ASM_ARCH_PROCESSOR_H +#define __ASM_ARCH_PROCESSOR_H + +//#define EISA_bus 0 +//#define EISA_bus__is_a_macro +//#define MCA_bus 0 +//#define MCA_bus__is_a_macro +// +//#define TASK_SIZE (0x01a00000UL) + +#endif +#endif /* end_of_not */ diff --git a/include/asm-arm/arch-moxart/serial.h b/include/asm-arm/arch-moxart/serial.h new file mode 100644 index 00000000..6ecf0ebc --- /dev/null +++ b/include/asm-arm/arch-moxart/serial.h @@ -0,0 +1,13 @@ +#ifndef CPE_SERIAL_H +#define CPE_SERIAL_H + +#include +#include + +#define BASE_BAUD (CONFIG_UART_CLK/16) + +/* Standard COM flags */ +#define EXTRA_SERIAL_PORT_DEFNS +#define STD_SERIAL_PORT_DEFNS +#endif + diff --git a/include/asm-arm/arch-moxart/system.h b/include/asm-arm/arch-moxart/system.h new file mode 100644 index 00000000..5bcd97c7 --- /dev/null +++ b/include/asm-arm/arch-moxart/system.h @@ -0,0 +1,36 @@ +/* + * linux/include/asm-armnommu/arch-cpe/system.h + * + * Copyright (c) 1999 Nicolas Pitre + * Copyright (c) 2001 RidgeRun, Inc (http://www.ridgerun.org) + * + */ +#include + +static inline void arch_idle(void) +{ + cpu_do_idle(); +// while (!current->need_resched && !hlt_counter); +} + +extern inline void arch_reset(char mode) +{ +#if 1 // add by Victor Yu. 11-23-2005 + if ( mode == 's' ) { + // Jump to ROM address 0 + cpu_reset(0); + } else { + // reset the CPU + // frist set the counter to 1 + *(unsigned int *)(CPE_WATCHDOG_BASE+4) = 1; + + // to start the watch dog + *(unsigned int *)(CPE_WATCHDOG_BASE+8) = 0x5ab9; + + // set to reset the CPU + *(unsigned int *)(CPE_WATCHDOG_BASE+12) = 0x03; + } +#endif + /* REVISIT --gmcnutt */ +} + diff --git a/include/asm-arm/arch-moxart/time.h b/include/asm-arm/arch-moxart/time.h new file mode 100644 index 00000000..c89875b9 --- /dev/null +++ b/include/asm-arm/arch-moxart/time.h @@ -0,0 +1,36 @@ +/* + time.h + maintened by ivan wang 2004/8/18 11:25 +*/ + + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ + +#include +#include +#include +#include "cpe_time.h" +#include +#include + + +#endif /* __ASM_ARCH_TIME_H__ */ +#if 0 // mask by Victor Yu. 11-17-2005 +#include + + +#define TIMER1_COUNT 0x0 +#define TIMER1_LOAD 0x4 +#define TIMER1_MATCH1 0x8 +#define TIMER1_MATCH2 0xC +#define TIMER2_COUNT 0x10 +#define TIMER2_LOAD 0x14 +#define TIMER2_MATCH1 0x18 +#define TIMER2_MATCH2 0x1C +#define TIMER3_COUNT 0x20 +#define TIMER3_LOAD 0x24 +#define TIMER3_MATCH1 0x28 +#define TIMER3_MATCH2 0x2C +#define TIMER_CR 0x30 +#endif diff --git a/include/asm-arm/arch-moxart/timex.h b/include/asm-arm/arch-moxart/timex.h new file mode 100644 index 00000000..dfa271e0 --- /dev/null +++ b/include/asm-arm/arch-moxart/timex.h @@ -0,0 +1,13 @@ +/* + * timex.h: + * 2001 Mac Wang + */ +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#include + +#define CLOCK_TICK_RATE (((fMCLK_MHz/100))*2) +#define fMCLK_MHz 33000000 + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-moxart/uncompress.h b/include/asm-arm/arch-moxart/uncompress.h new file mode 100644 index 00000000..9d238dab --- /dev/null +++ b/include/asm-arm/arch-moxart/uncompress.h @@ -0,0 +1,76 @@ +#include + +static void delayputs(void) +{ + volatile unsigned int i=100; + while(i--) + ; +} +/* + * If we need to do some setup prior to decompression (like initializing the + * UART if we want to use puts() above) then we define it here. Punt. + */ + +#define SERIAL_THR 0x00 /* Transmitter Holding Register(Write).*/ +#define SERIAL_RBR 0x00 /* Receive Buffer register (Read).*/ +#define SERIAL_IER 0x04 /* Interrupt Enable register.*/ +#define SERIAL_IIR 0x08 /* Interrupt Identification register(Read).*/ +#define SERIAL_FCR 0x08 /* FIFO control register(Write).*/ +#define SERIAL_EFR 0x08 // ????????????????????? +#define SERIAL_LCR 0x0C /* Line Control register.*/ +#define SERIAL_MCR 0x10 /* Modem Control Register.*/ +#define SERIAL_LSR 0x14 /* Line status register(Read) .*/ +#define SERIAL_MSR 0x18 /* Modem Status register (Read).*/ +#define SERIAL_SPR 0x1C /* Scratch pad register */ +#define SERIAL_DLL 0x0 /* Divisor Register LSB */ +#define SERIAL_DLM 0x4 /* Divisor Register MSB */ +#define SERIAL_PSR 0x8 /* Prescale Divison Factor */ + + +/* LSR Register */ +#define SERIAL_LSR_DR 0x1 /* Data Ready */ +#define SERIAL_LSR_OE 0x2 /* Overrun Error */ +#define SERIAL_LSR_PE 0x4 /* Parity Error */ +#define SERIAL_LSR_FE 0x8 /* Framing Error */ +#define SERIAL_LSR_BI 0x10 /* Break Interrupt */ +#define SERIAL_LSR_THRE 0x20 /* THR Empty */ +#define SERIAL_LSR_TE 0x40 /* Transmitte Empty */ +#define SERIAL_LSR_DE 0x80 /* FIFO Data Error */ + + +#define PUTS_UART_BASE CPE_UART1_BASE + +#if 0 // mask by Victor Yu. 05-19-2005 +static void puts(const char *s) +#else // add by Victor Yu. 05-19-2005 +static void putstr(const char *s) +#endif +{ + while (*s) + { + volatile unsigned int status=0; + do + { + status = *(unsigned char *)(PUTS_UART_BASE+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(PUTS_UART_BASE+SERIAL_THR) = *s; + + if (*s == '\n') + { + + do + { + status = *(unsigned char *)(PUTS_UART_BASE+SERIAL_LSR); + } + while (!((status & SERIAL_LSR_THRE)==SERIAL_LSR_THRE) ); + + *(unsigned char *)(PUTS_UART_BASE+SERIAL_THR) = '\r'; + } + s++; + } +} + +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-p2001/debug-macro.S b/include/asm-arm/arch-p2001/debug-macro.S new file mode 100644 index 00000000..ab075732 --- /dev/null +++ b/include/asm-arm/arch-p2001/debug-macro.S @@ -0,0 +1,37 @@ +/* linux/include/asm-arm/arch-p2001/debug-macro.S + * + * Debugging macro include header + * + * by Hyok S. Choi + * + * 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. + * +*/ + + /* UART base address */ + .macro addruart,rx + mov \rx, #0x00140000 + .endm + + /* send char */ + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + /* wait for end of transmission */ + .macro busyuart,rd,rx +1001: ldrb \rd, [\rx, #0x24] + cmp \rd, #0 + bne 1001b + .endm + + /* wait for fifo space */ + /* quickest way here: test for >0x20 chars in fifo */ + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x24] + tst \rd, #0x20 + bne 1001b + .endm + diff --git a/include/asm-arm/arch-p2001/dma.h b/include/asm-arm/arch-p2001/dma.h new file mode 100644 index 00000000..20c6366d --- /dev/null +++ b/include/asm-arm/arch-p2001/dma.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-armnommu/arch-p2001/dma.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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 +#include + +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x01000000 +#define MAX_DMA_TRANSFER_SIZE 0x100000 +/* TODO TODO TODO TODO TODO */ + +/***************************************************************************/ +/* this means that We will use arch/arm/mach/dma.h i.e generic dma module */ +#define MAX_DMA_CHANNELS 0 +/***************************************************************************/ + +#define arch_dma_init(dma_chan) +#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-p2001/entry-macro.S b/include/asm-arm/arch-p2001/entry-macro.S new file mode 100644 index 00000000..7b0a0f91 --- /dev/null +++ b/include/asm-arm/arch-p2001/entry-macro.S @@ -0,0 +1,168 @@ +/* + * linux/arch/armnommu/mach-p2001/entry-macro.S + * + * Copyright (C) 2004 Tobias Lorenz + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + * 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 + +#define Adr_INT_CTRL_BASE 0x00130000 +#define REL_Adr_Main_NFIQ_Int_Ctrl 0x00 +#define REL_Adr_Main_NIRQ_Int_Ctrl 0x04 +#define REL_Adr_Status_NFIQ 0x08 +#define REL_Adr_Status_NIRQ 0x0c + +#define NR_IRQS 27 /* 27 Interrupts: INT 0..26 */ + + + /* disable FIQ */ + .macro disable_fiq + .endm + + + /* + * get the irq number(at least), and others. + * irqnr : The number of the IRQ that you want to raise. + * irqstat: ??? + * base : The comments suggest this is a prioritization mechanism, but it doesn't appear + * to be actually used anywhere. That's why many of the irq_prio_table macros are empty. + * flags : This is non-obvious, but you'll notice that every get_irqnr_and_base macro + * does a test at the end of the macro. If you don't have a flag (I think it's the Z) set, + * then you'll never call do_IRQ. It's basically a check to avoid calling do_IRQ if you had + * a spurious interrupt (or one that was masked). + */ + /* irqnr=r0 irqstat=r6 base=r5 tmp=lr */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov \irqstat, #Adr_INT_CTRL_BASE + ldr \irqstat, [\irqstat, #REL_Adr_Status_NIRQ] + + mov \irqnr, #IRQ_EU0_DATA + tst \irqstat, #(1< + +#ifndef __ASSEMBLY__ + +/* DMA descriptor */ +typedef struct { + u32 stat; /* status: own, start, end, offset, status */ + u32 cntl; /* control: loop, int, type, channel, length */ + char *buf; /* buffer */ + void *next; /* nextdsc */ +} DMA_DSC; + + +/* The address definitions are from asic_bf.h */ +typedef struct { // 0x00100000U + volatile unsigned int reserved1[0x3]; + volatile unsigned int ArmDmaPri; // 0x0000000CU + volatile unsigned int SDRAM_Ctrl; // 0x00000010U + volatile unsigned int ExtMem_Ctrl; // 0x00000014U + volatile unsigned int WaitState_Ext; // 0x00000018U + volatile unsigned int WaitState_Asic; // 0x0000001CU + volatile unsigned int TOP; // 0x00000020U + volatile unsigned int reserved2[0x3]; + volatile unsigned int Adr1_EQ_30Bit; // 0x00000030U + volatile unsigned int Adr2_EQ_30Bit; // 0x00000034U + volatile unsigned int Adr3_EQ_30Bit; // 0x00000038U + volatile unsigned int Dat3_EQ_32Bit; // 0x0000003CU + volatile unsigned int Adr4_HE_20Bit; // 0x00000040U + volatile unsigned int Adr4_LT_20Bit; // 0x00000044U + volatile unsigned int Adr5_HE_20Bit; // 0x00000048U + volatile unsigned int Adr5_LT_20Bit; // 0x0000004CU + volatile unsigned int Adr_Control; // 0x00000050U + volatile unsigned int ABORT_IA_32Bit; // 0x00000054U +} *P2001_SYS_regs_ptr; +#define P2001_SYS ((volatile P2001_SYS_regs_ptr) 0x00100000UL) + +typedef struct { // 0x00110000U + volatile unsigned int Timer1; // 0x00000000U + volatile unsigned int Timer2; // 0x00000004U + volatile unsigned int TIMER_PRELOAD; // 0x00000008U + volatile unsigned int Timer12_PreDiv; // 0x0000000CU + volatile unsigned int TIMER_INT; // 0x00000010U + volatile unsigned int Freerun_Timer; // 0x00000014U + volatile unsigned int WatchDog_Timer; // 0x00000018U + volatile unsigned int reserved1[0x1]; + volatile unsigned int PWM_CNT; // 0x00000020U + volatile unsigned int PWM_CNT2; // 0x00000024U + volatile unsigned int reserved2[0x2]; + volatile unsigned int PLL_12000_config; // 0x00000030U + volatile unsigned int PLL_12288_config; // 0x00000034U + volatile unsigned int DIV_12288_config; // 0x00000038U + volatile unsigned int MOD_CNT_768; // 0x0000003CU + volatile unsigned int FSC_IRQ_STATUS; // 0x00000040U + volatile unsigned int FSC_CONFIG; // 0x00000044U + volatile unsigned int FSC_CONSTRUCT; // 0x00000048U + volatile unsigned int FSC_base_clk_reg; // 0x0000004CU + volatile unsigned int SYSCLK_SHAPE; // 0x00000050U + volatile unsigned int SDRAMCLK_SHAPE; // 0x00000054U + volatile unsigned int RING_OSZI; // 0x00000058U +} *P2001_TIMER_regs_ptr; +#define P2001_TIMER ((volatile P2001_TIMER_regs_ptr) 0x00110000UL) + +typedef struct { // 0x00120000U + volatile unsigned int reserved1[0x5]; + volatile unsigned int GPIO_Config; // 0x00000014U + volatile unsigned int GPIO_INT; // 0x00000018U + volatile unsigned int GPIO_Out; // 0x0000001CU + volatile unsigned int GPIO_IN; // 0x00000020U + volatile unsigned int GPIO_En; // 0x00000024U + volatile unsigned int PIN_MUX; // 0x00000028U + volatile unsigned int NRES_OUT; // 0x0000002CU + volatile unsigned int GPIO2_Out; // 0x00000030U + volatile unsigned int GPIO2_IN; // 0x00000034U + volatile unsigned int GPIO2_En; // 0x00000038U + volatile unsigned int GPIO_INT_SEL; // 0x0000003CU + volatile unsigned int GPI3_IN; // 0x00000040U + volatile unsigned int GPO4_OUT; // 0x00000044U +} *P2001_GPIO_regs_ptr; +#define P2001_GPIO ((volatile P2001_GPIO_regs_ptr) 0x00120000UL) + +typedef struct { // 0x00130000U + volatile unsigned int Main_NFIQ_Int_Ctrl; // 0x00000000U + volatile unsigned int Main_NIRQ_Int_Ctrl; // 0x00000004U + volatile unsigned int Status_NFIQ; // 0x00000008U + volatile unsigned int Status_NIRQ; // 0x0000000CU +} *P2001_INT_CTRL_regs_ptr; +#define P2001_INT_CTRL ((volatile P2001_INT_CTRL_regs_ptr) 0x00130000UL) + +typedef struct { // 0x00130000U + volatile unsigned int IRQ_STATUS; // 0x00000000U + volatile unsigned int FIQ_STATUS; // 0x00000004U + volatile unsigned int RAW_INTR; // 0x00000008U + volatile unsigned int INT_SELECT; // 0x0000000CU + volatile unsigned int INT_ENABLE; // 0x00000010U + volatile unsigned int INT_ENCLEAR; // 0x00000014U + volatile unsigned int SOFTINT; // 0x00000018U + volatile unsigned int SOFTINT_CLEAR; // 0x0000001CU + volatile unsigned int PROTECTION; // 0x00000020U + volatile unsigned int reserved1[0x3]; + volatile unsigned int CUR_VECT_ADDR; // 0x00000030U + volatile unsigned int DEF_VECT_ADDR; // 0x00000034U + volatile unsigned int reserved2[0x32]; + volatile unsigned int VECT_ADDR[16]; // 0x00000100U - 0x013CU + volatile unsigned int reserved3[0x30]; + volatile unsigned int VECT_CNTL[16]; // 0x00000200U - 0x023CU +} *P2001_LPEC_VIC_regs_ptr; +#define P2001_LPEC_VIC ((volatile P2001_LPEC_VIC_regs_ptr) 0x00130000UL) + +typedef union { // 0x00140000U + struct { // write + volatile unsigned int TX[4]; // 0x00000000U-0x000CU + volatile unsigned int Baudrate; // 0x00000010U + volatile unsigned int reserved1[0x3]; + volatile unsigned int Config; // 0x00000020U + volatile unsigned int Clear; // 0x00000024U + volatile unsigned int Echo_EN; // 0x00000028U + volatile unsigned int IRQ_Status; // 0x0000002CU + } w; // write + + struct { // read + volatile unsigned int RX[4]; // 0x00000000U-0x000CU + volatile unsigned int reserved1[0x4]; + volatile unsigned int PRE_STATUS; // 0x00000020U + volatile unsigned int STATUS; // 0x00000024U + volatile unsigned int reserved2[0x1]; + volatile unsigned int IRQ_Status; // 0x0000002CU + } r; // read +} *P2001_UART_regs_ptr; +#define P2001_UART ((volatile P2001_UART_regs_ptr) 0x00140000UL) + +typedef struct { // 0x00150000U + struct { + volatile unsigned char S[0x100]; // 0x00000000U + volatile unsigned char H[0x100]; // 0x00000100U + } BASE[8]; + struct { + volatile unsigned char S[0x100]; // 0x00001000U + volatile unsigned char H[0x100]; // 0x00001100U + } HDLC; + struct { + volatile unsigned char S[0x100]; // 0x00001200U + volatile unsigned char H[0x100]; // 0x00001300U + } DTMF; + volatile unsigned int reserved1[0x300]; + struct { + volatile unsigned int Control; // 0x00002000U + volatile unsigned int Timeslot_Enable; // 0x00002004U + volatile unsigned int Status; // 0x00002008U + volatile unsigned int reserved1[0x1]; + } CTS[8]; + struct { + volatile unsigned int Control; // 0x00002080U + volatile unsigned int Status; // 0x00002084U + volatile unsigned int reserved1[0x2]; + } HDLC_WB; + struct { + volatile unsigned int Control; // 0x00002080U + volatile unsigned int Status; // 0x00002084U + volatile unsigned int reserved1[0x2]; + } DTMF_WB; + volatile unsigned int Peripheral_Frame_Sync[4]; // 0x000020A0U - 0x20ACU + volatile unsigned int BSCK_FSC_Select; // 0x000020B0U +} *P2001_PCM_HW_regs_ptr; +#define P2001_PCM_HW ((volatile P2001_PCM_HW_regs_ptr) 0x00150000UL) + +typedef struct { // 0x00160000U + volatile unsigned int COEF_1394_697; // 0x00000000U + volatile unsigned int COEF_1540_770; // 0x00000004U + volatile unsigned int COEF_1704_852; // 0x00000008U + volatile unsigned int COEF_1882_941; // 0x0000000CU + volatile unsigned int COEF_2418_1209; // 0x00000010U + volatile unsigned int COEF_2672_1336; // 0x00000014U + volatile unsigned int COEF_2954_1477; // 0x00000018U + volatile unsigned int COEF_3266_1633; // 0x0000001CU + volatile unsigned int COEF_SIGNS; // 0x00000020U + volatile unsigned int RECURSION_COUNTER; // 0x00000024U + volatile unsigned int LAW_SCALE; // 0x00000028U + volatile unsigned int reserved1[0x3]; + volatile unsigned int MAC_TABLE_LO_N; // 0x00000038U + volatile unsigned int MAC_TABLE_HI_N; // 0x0000003CU + volatile unsigned int MAG_TONE[8]; // 0x00000040U + volatile unsigned int MAG_OVERTONE[8]; // 0x00000060U + /* Basetone T = 0:697Hz / 1:770Hz / ... / 7:1633Hz */ + struct { + volatile unsigned int TAP1; // 0x00000080U + volatile unsigned int TAP2; // 0x00000084U + } TONE[8]; + /* Overtone OT= 0:1394Hz / 1:1540Hz / ... / 7:3266Hz */ + struct { + volatile unsigned int TAP1; // 0x000000C0U + volatile unsigned int TAP2; // 0x000000C4U + } OVERTONE[8]; +} *P2001_DTMF_COEF_regs_ptr; +#define P2001_DTMF_COEF(x) ((volatile P2001_DTMF_COEF_regs_ptr) ((unsigned int) 0x00160000UL+(0x100UL*(x)))) /* x = 0..31 */ + +typedef struct { // 0x00162000U + volatile unsigned int ENA_REG; // 0x00000000U + volatile unsigned int IRQ_STAT_REG; // 0x00000004U +} *P2001_DTMF_regs_ptr; +#define P2001_DTMF ((volatile P2001_DTMF_regs_ptr) 0x00162000UL) + +typedef struct { // 0x00164000U + volatile unsigned int VAL_LO; // 0x00000000U + volatile unsigned int VAL_HI; // 0x00000004U + volatile unsigned int RES; // 0x00000008U +} *P2001_MAC_CMP_regs_ptr; +#define P2001_MAC_CMP ((volatile P2001_MAC_CMP_regs_ptr) 0x00164000UL) + +typedef struct { // 0x00170_00U _=0,4 + volatile unsigned int B1_REC; // 0x00000000U + volatile unsigned int B1_SEND; // 0x00000004U + volatile unsigned int B2_REC; // 0x00000008U + volatile unsigned int B2_SEND; // 0x0000000CU + volatile unsigned int D_REC; // 0x00000010U + volatile unsigned int D_SEND; // 0x00000014U + volatile unsigned int E_REC; // 0x00000018U + volatile unsigned int CTRL; // 0x0000001CU + volatile unsigned int INT_EN; // 0x00000020U + volatile unsigned int INT_STATUS; // 0x00000024U + volatile unsigned int FSC_PHASE; // 0x00000028U + volatile unsigned int reserved1[0x25]; + /* HFC-S+ Registers */ + volatile unsigned int STATES; // 0x000000C0U (HFC-S+ Adr 30) + volatile unsigned int SCTRL; // 0x000000C4U (HFC-S+ Adr 31) + volatile unsigned int SCTRL_E; // 0x000000C8U (HFC-S+ Adr 32) + volatile unsigned int SCTRL_R; // 0x000000CCU (HFC-S+ Adr 33) + volatile unsigned int SQ_REC_SEND; // 0x000000D0U (HFC-S+ Adr 34) + volatile unsigned int reserved2[0x2]; + volatile unsigned int CLKDEL; // 0x000000DCU (HFC-S+ Adr 37) +} *P2001_S0_regs_ptr; +#define P2001_S0(x) ((volatile P2001_S0_regs_ptr) ((unsigned int) 0x00170000UL+(0x400UL*(x)))) /* x = 0..1 */ + +typedef struct { // 0x0018_000U _=0,1,2,3 + volatile DMA_DSC * RMAC_DMA_DESC; // 0x00000000U + volatile unsigned int RMAC_DMA_CNTL; // 0x00000004U + volatile unsigned int RMAC_DMA_STAT; // 0x00000008U + volatile unsigned int RMAC_DMA_EN; // 0x0000000CU + volatile unsigned int RMAC_CNTL; // 0x00000010U + volatile unsigned int RMAC_TLEN; // 0x00000014U + volatile unsigned int RMAC_PHYU; // 0x00000018U + volatile unsigned int RMAC_PHYL; // 0x0000001CU + volatile unsigned int RMAC_PFM[8]; // 0x00000020U-0x003CU + volatile unsigned int RMAC_MIB[6]; // 0x00000040U-0x0054U + volatile unsigned int reserved1[0x1e8]; + volatile unsigned int RMAC_DMA_DATA; // 0x000007F8U + volatile unsigned int RMAC_DMA_ADR; // 0x000007FCU + volatile DMA_DSC * TMAC_DMA_DESC; // 0x00000800U + volatile unsigned int TMAC_DMA_CNTL; // 0x00000804U + volatile unsigned int TMAC_DMA_STAT; // 0x00000808U + volatile unsigned int TMAC_DMA_EN; // 0x0000080CU + volatile unsigned int TMAC_CNTL; // 0x00000810U + volatile unsigned int TMAC_MIB[2]; // 0x00000814U-0x0818U + volatile unsigned int reserved2[0x1]; + volatile unsigned int MU_CNTL; // 0x00000820U + volatile unsigned int MU_DATA; // 0x00000824U + volatile unsigned int MU_DIV; // 0x00000828U + volatile unsigned int CONF_RMII; // 0x0000082CU + volatile unsigned int reserved3[0x1f2]; + volatile unsigned int TMAC_DMA_DATA; // 0x00000FF8U + volatile unsigned int TMAC_DMA_ADR; // 0x00000FFCU +} *P2001_ETH_regs_ptr; +#define P2001_EU(x) ((volatile P2001_ETH_regs_ptr) ((unsigned int) 0x00180000UL+(0x1000UL*(x)))) /* x = 0..3 */ +#define P2001_MU P2001_EU(0) + +typedef struct { // 0x00184__0U _=00,...7C + volatile unsigned int v_tx_dma_desc; // 0x00000000U + volatile unsigned int reserved1[0x1]; + volatile unsigned int v_tx_dma_stat; // 0x00000008U + volatile unsigned int v_tx_dma_en; // 0x0000000CU + volatile unsigned int v_rx_dma_desc; // 0x00000010U + volatile unsigned int v_rx_dma_cntl; // 0x00000014U + volatile unsigned int v_rx_dma_stat; // 0x00000018U + volatile unsigned int v_rx_dma_en; // 0x0000001CU + volatile unsigned int v_mode; // 0x00000020U + volatile unsigned int v_es_reg; // 0x00000024U + volatile unsigned int v_es_stat; // 0x00000028U + volatile unsigned int reserved2[0x5]; +} *P2001_HDLC_DMA_regs_ptr[32]; +#define P2001_HDLC_DMA ((volatile P2001_HDLC_regs_ptr) 0x00184000UL) + +typedef struct { // 0x001847F0U + volatile unsigned int reserved1[0x2]; + volatile unsigned int rx_data; // 0x000007F8U + volatile unsigned int rx_adr; // 0x000007FCU + volatile unsigned int mts_tsa_base; // 0x00000800U + volatile unsigned int reserved2[0x183]; + volatile unsigned int pcm_cntl; // 0x00000E10U + volatile unsigned int reserved3[0x1]; + volatile unsigned int frame_end; // 0x00000E18U + volatile unsigned int v_data_stat; // 0x00000E1CU + volatile unsigned int v_err_stat; // 0x00000E20U + volatile unsigned int reserved4[0x75]; + volatile unsigned int tx_data; // 0x00000FF8U + volatile unsigned int tx_adr; // 0x00000FFCU +} *P2001_HDLC_regs_ptr; +#define P2001_HDLC ((volatile P2001_HDLC_regs_ptr) 0x001847F0UL) + +typedef struct { // 0x00190000U + volatile unsigned int FUNC_ADDR; // 0x00000000U + volatile unsigned int MODE_CTRL; // 0x00000004U + volatile unsigned int CTRL; // 0x00000008U + volatile unsigned int MAIN_EVENT; // 0x0000000CU + volatile unsigned int MAIN_EVENT_MSK; // 0x00000010U + volatile unsigned int STATIC_EVENT; // 0x00000014U + volatile unsigned int STATIC_EVENT_MSK; // 0x00000018U + volatile unsigned int FRM_TIMER; // 0x0000001CU + volatile unsigned int OUT_EP_SEL; // 0x00000020U + volatile unsigned int OUT_DATA; // 0x00000024U + volatile unsigned int OUT_CMD; // 0x00000028U + volatile unsigned int OUT_STAT; // 0x0000002CU + volatile unsigned int IN_EP_SEL; // 0x00000030U + volatile unsigned int IN_DATA; // 0x00000034U + volatile unsigned int IN_CMD; // 0x00000038U + volatile unsigned int reserved1[0x1]; + volatile unsigned int OEP_ENA; // 0x00000040U + volatile unsigned int IEP_ENA; // 0x00000044U + volatile unsigned int OEP_STALL; // 0x00000048U + volatile unsigned int IEP_STALL; // 0x0000004CU + volatile unsigned int OUT_EVENT; // 0x00000050U + volatile unsigned int OUT_EVENT_MSK; // 0x00000054U + volatile unsigned int IN_EVENT; // 0x00000058U + volatile unsigned int IN_EVENT_MSK; // 0x0000005CU + volatile unsigned int IN_ISO_CONF_REG; // 0x00000060U + volatile unsigned int OUT_ISO_CONF_REG; // 0x00000064U + volatile unsigned int IN_PTR_REG; // 0x00000068U + volatile unsigned int OUT_PTR_REG; // 0x0000006CU + volatile unsigned int reserved2[0x3]; + volatile unsigned int CTRL_REG; // 0x0000007CU +} *P2001_USB_regs_ptr; +#define P2001_USB ((volatile P2001_USB_regs_ptr) 0x00190000UL) + +typedef volatile unsigned char *P2001_USB_FIFO_ptr[64]; +#define P2001_USB_EPxIN(x) ((volatile P2001_USB_FIFO_ptr) ((unsigned int) 0x001A0000UL+(0x40UL*(x)))) /* x = 0..5 */ +#define P2001_USB_EPxOUT(x) ((volatile P2001_USB_FIFO_ptr) ((unsigned int) 0x001A0180UL+(0x40UL*(x)))) /* x = 0..5 */ + +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-p2001/io.h b/include/asm-arm/arch-p2001/io.h new file mode 100644 index 00000000..390dd764 --- /dev/null +++ b/include/asm-arm/arch-p2001/io.h @@ -0,0 +1,36 @@ +/* + * linux/include/asm-armnommu/arch-p2001/io.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + /* Used in kernel/resource.c */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __mem_pci(a) (a) + +#define __io(a) ((unsigned long)(a)) + +/* + * Defining these two gives us ioremap for free. See asm/io.h. + * --gmcnutt + */ +#define iomem_valid_addr(iomem,size) (1) +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-p2001/irq.h b/include/asm-arm/arch-p2001/irq.h new file mode 100644 index 00000000..8e857059 --- /dev/null +++ b/include/asm-arm/arch-p2001/irq.h @@ -0,0 +1,32 @@ +/* + * linux/include/asm-armnommu/arch-p2001/irq.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARCH_IRQ_H__ +#define __ASM_ARCH_IRQ_H__ + + +#include +#include +#include +#include + +#define fixup_irq(x) (x) + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void p2001_mask_irq(unsigned int irq); +extern void p2001_unmask_irq(unsigned int irq); +extern void p2001_mask_ack_irq(unsigned int irq); + +extern void p2001_init_irq(void); + +#define irq_init_irq p2001_init_irq + +#endif /* __ASM_ARCH_IRQ_H__ */ diff --git a/include/asm-arm/arch-p2001/irqs.h b/include/asm-arm/arch-p2001/irqs.h new file mode 100644 index 00000000..da75554c --- /dev/null +++ b/include/asm-arm/arch-p2001/irqs.h @@ -0,0 +1,42 @@ +/* + * linux/include/asm-armnommu/arch-p2001/irqs.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARCH_IRQS_H__ +#define __ASM_ARCH_IRQS_H__ + +#define IRQ_USB 0 +#define IRQ_UART 1 +#define IRQ_PWM 2 +#define IRQ_FSC 3 +#define IRQ_GPIO 4 +#define IRQ_PFS0 5 +#define IRQ_PFS1 6 +#define IRQ_PFS2 7 +#define IRQ_PFS3 8 +#define IRQ_SO0 9 +#define IRQ_SO1 10 +#define IRQ_DTMF 11 +#define IRQ_WATCHDOG 12 +#define IRQ_PCMHW 13 +#define IRQ_HDLC_MTS 14 +#define IRQ_HDLC_ERROR 15 +#define IRQ_HDLC_DATA 16 +#define IRQ_EU0_DATA 17 +#define IRQ_EU0_ERROR 18 +#define IRQ_EU1_DATA 19 +#define IRQ_EU1_ERROR 20 +#define IRQ_EU2_DATA 21 +#define IRQ_EU2_ERROR 22 +#define IRQ_EU3_DATA 23 +#define IRQ_EU3_ERROR 24 +#define IRQ_TIMER1 25 +#define IRQ_TIMER2 26 + +#endif /* __ASM_ARCH_IRQS_H__ */ diff --git a/include/asm-arm/arch-p2001/memory.h b/include/asm-arm/arch-p2001/memory.h new file mode 100644 index 00000000..1f60d2e8 --- /dev/null +++ b/include/asm-arm/arch-p2001/memory.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/arch-p2001/memory.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-p2001/param.h b/include/asm-arm/arch-p2001/param.h new file mode 100644 index 00000000..f5e02eb1 --- /dev/null +++ b/include/asm-arm/arch-p2001/param.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-armnommu/arch-p2001/param.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-p2001/system.h b/include/asm-arm/arch-p2001/system.h new file mode 100644 index 00000000..927742f4 --- /dev/null +++ b/include/asm-arm/arch-p2001/system.h @@ -0,0 +1,32 @@ +/* + * linux/include/asm-armnommu/arch-p2001/system.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0); +} + +#endif diff --git a/include/asm-arm/arch-p2001/timex.h b/include/asm-arm/arch-p2001/timex.h new file mode 100644 index 00000000..e2d435d9 --- /dev/null +++ b/include/asm-arm/arch-p2001/timex.h @@ -0,0 +1,17 @@ +/* + * linux/include/asm-armnommu/arch-p2001/timex.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE (CONFIG_SYSCLK) +//#define CLOCK_TICK_RATE 12288000 + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-p2001/uncompress.h b/include/asm-arm/arch-p2001/uncompress.h new file mode 100644 index 00000000..88cfedc1 --- /dev/null +++ b/include/asm-arm/arch-p2001/uncompress.h @@ -0,0 +1,43 @@ +/* + * linux/include/asm-armnommu/arch-p2001/uncompress.h + * + * Copyright (C) 2004 Tobias Lorenz + * + * 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. + */ + +#ifndef __UNCOMPRESS_H__ +#define __UNCOMPRESS_H__ + +#include + +static __inline__ void putc(char c) +{ + while ((P2001_UART->r.STATUS & 0x3f) > 0) + barrier(); + P2001_UART->w.TX[0] = c; +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif diff --git a/include/asm-arm/arch-p2001/vmalloc.h b/include/asm-arm/arch-p2001/vmalloc.h new file mode 100644 index 00000000..24114263 --- /dev/null +++ b/include/asm-arm/arch-p2001/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-armnommu/arch-espd_4510b/vmalloc.h + * + * Copyright (C) 2000 Russell King. + * modified by Hyok S. Choi + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_P2001_SDRAM_SIZE (0x01000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_P2001_SDRAM_SIZE) diff --git a/include/asm-arm/arch-s3c24a0/S3C24A0.h b/include/asm-arm/arch-s3c24a0/S3C24A0.h new file mode 100644 index 00000000..d8294164 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/S3C24A0.h @@ -0,0 +1,1462 @@ +/* + * linux/include/asm-arm/arch-s3c24a0/S3C24A0.h + * + * $Id: S3C24A0.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + */ + +#ifndef _S3C24A0_H_ +#define _S3C24A0_H_ + +#include "hardware.h" +#include "bitfield.h" + +/* + * clock and power ( chapter 32 ) + */ + +#define LOCKTIME __REG(0x40000000) +#define XTALWSET __REG(0x40000004) +#define MPLLCON __REG(0x40000010) +#define UPLLCON __REG(0x40000014) +#define CLKCON __REG(0x40000020) +#define CLKSRC __REG(0x40000024) +#define CLKDIVN __REG(0x40000028) +#define POWERMAN __REG(0x40000030) +#define SOFTRST __REG(0x40000038) + +/* fields */ +#define fLOCK_U Fld(12,16) /* UPLL lock time in LOCKTIME */ +#define fLOCK_M Fld(12,0) /* MPLL lock time in LOCKTIME */ +#define fXTAL_U Fld(16,16) /* UPLL wait time in XTALWSET */ +#define fXTAL_M Fld(16,0) /* MPLL wait time in XTALWSET */ +#define fPLL_MDIV Fld(8,12) +#define fPLL_PDIV Fld(6,4) +#define fPLL_SDIV Fld(2,0) +#define fEXTDIV Fld(3,0) /* external clock div. in CLKSRC */ +#define fCLK_CAMDIV Fld(4,8) /* CAM clock div. in CLKDIV */ +#define fCLK_MP4DIV Fld(4,4) /* MPEG4 clock div. in CLKDIV */ +#define fCNFG_BF Fld(2,9) /* battery fault handling config in PWRMAN */ +#define fSLEEP_CODE Fld(8,0) /* sleep mode setting code in PWRMAN */ +/* bits */ +#define CLKCON_VPOST (1<<25) /* CLKCON */ +#define CLKCON_MPEG4IF (1<<24) +#define CLKCON_CAM_UPLL (1<<23) +#define CLKCON_LCD (1<<22) +#define CLKCON_CAM_HCLK (1<<21) +#define CLKCON_MPEG4 (1<<20) +#define CLKCON_KEYPAD (1<<19) +#define CLKCON_ADC (1<<18) +#define CLKCON_SD (1<<17) +#define CLKCON_MS (1<<16) /* memory stick */ +#define CLKCON_USBD (1<<15) +#define CLKCON_GPIO (1<<14) +#define CLKCON_IIS (1<<13) +#define CLKCON_IIC (1<<12) +#define CLKCON_SPI (1<<11) +#define CLKCON_UART1 (1<<10) +#define CLKCON_UART0 (1<<9) +#define CLKCON_PWM (1<<8) +#define CLKCON_USBH (1<<7) +#define CLKCON_AC97 (1<<6) +#define CLKCON_EAHB (1<<5) +#define CLKCON_IrDA (1<<4) +#define CLKCON_IDLE (1<<2) +#define CLKCON_MON (1<<1) +#define CLKCON_STOP (1<<0) +#define CLKSRC_OSC (1<<8) /* CLKSRC */ +#define CLKSRC_nUPLL (1<<7) +#define CLKSRC_nPLL (1<<5) +#define CLKSRC_EXT (1<<4) +#define CLKDIV_HCLK (1<<1) /* CLKDIV */ +#define CLKDIV_PCLK (1<<0) +#define PWRMAN_MASKTS (1<<8) /* PWRMAN */ + +//#define fCLKDIVN_BUS Fld(2,0) /* S3C24A0X */ +#define fCLKDIVN_BUS Fld(3,0) /* SW.LEE: S3C24A0A */ +#define CLKDIVN_BUS FExtr(CLKDIVN, fCLKDIVN_BUS) +#define CLKDIVN_CAM(x) FInsrt((x), fCLK_CAMDIV) +#define CLKDIVN_CAM_MSK FMsk(fCLK_CAMDIV) +#define CLKDIVN_CAM_VAL FExtr(CLKDIVN, fCLK_CAMDIV) +#define CLKDIVN_MP4(x) FInsrt((x), fCLK_MP4DIV) +#define CLKDIVN_MP4_MSK FMsk(fCLK_MP4DIV) + + +/* + * PWM timer ( chapter 7 ) + * + * five 16bit timers. + * two 8bit prescalers, four 4bit dividers + * programmable duty control of output waveform + * auto-load mode, one-shot pulse mode + * dead-zone generator + */ +#define bPWM_TIMER(Nb) __REG(0x44000000 + (Nb)) +#define bPWM_BUFn(Nb,x) bPWM_TIMER(0x0c + (Nb)*0x0c + (x)) +/* Registers */ +#define TCFG0 __REG(0x44000000) +#define TCFG1 __REG(0x44000004) +#define TCON __REG(0x44000008) +#define TCNTB0 __REG(0x4400000C) +#define TCMPB0 __REG(0x44000010) +#define TCNTO0 __REG(0x44000014) +#define TCNTB1 bPWM_BUFn(1,0x0) +#define TCMPB1 bPWM_BUFn(1,0x4) +#define TCNTO1 bPWM_BUFn(1,0x8) +#define TCNTB2 bPWM_BUFn(2,0x0) +#define TCMPB2 bPWM_BUFn(2,0x4) +#define TCNTO2 bPWM_BUFn(2,0x8) +#define TCNTB3 bPWM_BUFn(3,0x0) +#define TCMPB3 bPWM_BUFn(3,0x4) +#define TCNTO3 bPWM_BUFn(3,0x8) +#define TCNTB4 bPWM_BUFn(4,0x0) +#define TCNTO4 bPWM_BUFn(4,0x4) + +#define fTCFG0_DZONE Fld(8,16) /* the dead zone length (= timer 0) */ +#define fTCFG0_PRE1 Fld(8,8) /* prescaler value for time 2,3,4 */ +#define fTCFG0_PRE0 Fld(8,0) /* prescaler value for time 0,1 */ +#define SET_PRESCALER0(x) ({ TCFG0 = (TCFG0 & ~(0xff)) | (x); }) +#define GET_PRESCALER0() FExtr(TCFG0, fTCFG0_PRE0) +#define SET_PRESCALER1(x) ({ TCFG0 = (TCFG0 & ~(0xff << 8)) | ((x) << 8); }) +#define GET_PRESCALER1() FExtr(TCFG0, fTCFG0_PRE0) + +#define fTCFG1_DMA Fld(4,20) /* select DMA request channel */ +#define fTCFG1_T4MUX Fld(4,16) /* timer4 input mux */ +#define fTCFG1_T3MUX Fld(4,12) /* timer3 input mux */ +#define fTCFG1_T2MUX Fld(4,8) /* timer2 input mux */ +#define fTCFG1_T1MUX Fld(4,4) /* timer1 input mux */ +#define fTCFG1_T0MUX Fld(4,0) /* timer0 input mux */ +#define TIMER0_DIV(x) FInsrt((x), fTCFG1_T0MUX) +#define TIMER1_DIV(x) FInsrt((x), fTCFG1_T1MUX) +#define TIMER2_DIV(x) FInsrt((x), fTCFG1_T2MUX) +#define TIMER3_DIV(x) FInsrt((x), fTCFG1_T3MUX) +#define TIMER4_DIV(x) FInsrt((x), fTCFG1_T4MUX) + +#define fTCON_TIMER4 Fld(3,20) +#define fTCON_TIMER3 Fld(4,16) +#define fTCON_TIMER2 Fld(4,12) +#define fTCON_TIMER1 Fld(4,8) +#define fTCON_TIMER0 Fld(5,0) + +#define fCNTB Fld(16,0) +#define fCNTO Fld(16,0) +#define fCMPB Fld(16,0) + +#define TCFG0_DZONE(x) FInsrt((x), fTCFG0_DZONE) +#define TCFG0_PRE1(x) FInsrt((x), fTCFG0_PRE1) +#define TCFG0_PRE0(x) FInsrt((x), fTCFG0_PRE0) +#define TCON_4_AUTO (1 << 22) /* auto reload on/off for Timer 4 */ +#define TCON_4_UPDATE (1 << 21) /* manual Update TCNTB4 */ +#define TCON_4_ONOFF (1 << 20) /* 0: Stop, 1: start Timer 4 */ +#define COUNT_4_ON (TCON_4_ONOFF*1) +#define COUNT_4_OFF (TCON_4_ONOFF*0) +#define TCON_3_AUTO (1 << 19) /* auto reload on/off for Timer 3 */ +#define TCON_3_INVERT (1 << 18) /* 1: Inverter on for TOUT3 */ +#define TCON_3_MAN (1 << 17) /* manual Update TCNTB3,TCMPB3 */ +#define TCON_3_ONOFF (1 << 16) /* 0: Stop, 1: start Timer 3 */ +#define TCON_2_AUTO (1 << 15) /* auto reload on/off for Timer 3 */ +#define TCON_2_INVERT (1 << 14) /* 1: Inverter on for TOUT3 */ +#define TCON_2_MAN (1 << 13) /* manual Update TCNTB3,TCMPB3 */ +#define TCON_2_ONOFF (1 << 12) /* 0: Stop, 1: start Timer 3 */ +#define TCON_1_AUTO (1 << 11) /* auto reload on/off for Timer 3 */ +#define TCON_1_INVERT (1 << 10) /* 1: Inverter on for TOUT3 */ +#define TCON_1_MAN (1 << 9) /* manual Update TCNTB3,TCMPB3 */ +#define TCON_1_ONOFF (1 << 8) /* 0: Stop, 1: start Timer 3 */ +#define TCON_0_AUTO (1 << 3) /* auto reload on/off for Timer 3 */ +#define TCON_0_INVERT (1 << 2) /* 1: Inverter on for TOUT3 */ +#define TCON_0_MAN (1 << 1) /* manual Update TCNTB3,TCMPB3 */ +#define TCON_0_ONOFF (1 << 0) /* 0: Stop, 1: start Timer 3 */ + +#define TIMER3_ATLOAD_ON (TCON_3_AUTO*1) +#define TIMER3_ATLAOD_OFF FClrBit(TCON, TCON_3_AUTO) +#define TIMER3_IVT_ON (TCON_3_INVERT*1) +#define TIMER3_IVT_OFF (FClrBit(TCON, TCON_3_INVERT)) +#define TIMER3_MANUP (TCON_3_MAN*1) +#define TIMER3_NOP (FClrBit(TCON, TCON_3_MAN)) +#define TIMER3_ON (TCON_3_ONOFF*1) +#define TIMER3_OFF (FClrBit(TCON, TCON_3_ONOFF)) +#define TIMER2_ATLOAD_ON (TCON_2_AUTO*1) +#define TIMER2_ATLAOD_OFF FClrBit(TCON, TCON_2_AUTO) +#define TIMER2_IVT_ON (TCON_2_INVERT*1) +#define TIMER2_IVT_OFF (FClrBit(TCON, TCON_2_INVERT)) +#define TIMER2_MANUP (TCON_2_MAN*1) +#define TIMER2_NOP (FClrBit(TCON, TCON_2_MAN)) +#define TIMER2_ON (TCON_2_ONOFF*1) +#define TIMER2_OFF (FClrBit(TCON, TCON_2_ONOFF)) +#define TIMER1_ATLOAD_ON (TCON_1_AUTO*1) +#define TIMER1_ATLAOD_OFF FClrBit(TCON, TCON_1_AUTO) +#define TIMER1_IVT_ON (TCON_1_INVERT*1) +#define TIMER1_IVT_OFF (FClrBit(TCON, TCON_1_INVERT)) +#define TIMER1_MANUP (TCON_1_MAN*1) +#define TIMER1_NOP (FClrBit(TCON, TCON_1_MAN)) +#define TIMER1_ON (TCON_1_ONOFF*1) +#define TIMER1_OFF (FClrBit(TCON, TCON_1_ONOFF)) +#define TIMER0_ATLOAD_ON (TCON_0_AUTO*1) +#define TIMER0_ATLAOD_OFF FClrBit(TCON, TCON_0_AUTO) +#define TIMER0_IVT_ON (TCON_0_INVERT*1) +#define TIMER0_IVT_OFF (FClrBit(TCON, TCON_0_INVERT)) +#define TIMER0_MANUP (TCON_0_MAN*1) +#define TIMER0_NOP (FClrBit(TCON, TCON_0_MAN)) +#define TIMER0_ON (TCON_0_ONOFF*1) +#define TIMER0_OFF (FClrBit(TCON, TCON_0_ONOFF)) + +#define TCON_TIMER1_CLR FClrFld(TCON, fTCON_TIMER1); +#define TCON_TIMER2_CLR FClrFld(TCON, fTCON_TIMER2); +#define TCON_TIMER3_CLR FClrFld(TCON, fTCON_TIMER3); + + +/* + * NAND ( chapter 4 ) + * + */ +#include "s3c24a0_nand.h" + +/* S3C24A0-A LCD CONTROLLER DEVICE ONLY */ +#ifdef CONFIG_ARCH_S3C24A0A +#define bLCD_CTL(Nb) __REG(0x4a000000 + (Nb)) +#define LCDCON1 bLCD_CTL(0x00) /* LCD CONTROL 1 */ +#define LCDCON2 bLCD_CTL(0x04) /* LCD CONTROL 2 */ +#define LCDTCON1 bLCD_CTL(0x08) /* LCD TIME CONTROL 1 */ +#define LCDTCON2 bLCD_CTL(0x0c) /* LCD TIME CONTROL 2 */ +#define LCDTCON3 bLCD_CTL(0x10) /* LCD TIME CONTROL 3 */ +#define LCDOSD1 bLCD_CTL(0x14) /* LCD OSD CONTROL REGISTER */ +#define LCDOSD2 bLCD_CTL(0x18) /* Foreground image(OSD Image) left top position set */ +#define LCDOSD3 bLCD_CTL(0x1c) /* Foreground image(OSD Image) right bottom position set */ +#define LCDSADDRB1 bLCD_CTL(0x20) /* Frame buffer start address 1 (Background buffer 1) */ +#define LCDSADDRB2 bLCD_CTL(0x24) /* Frame buffer start address 2 (Background buffer 2) */ +#define LCDSADDRF1 bLCD_CTL(0x28) /* Frame buffer start address 1 (Foreground buffer 1) */ +#define LCDSADDRF2 bLCD_CTL(0x2c) /* Frame buffer start address 2 (Foreground buffer 2) */ +#define LCDEADDRB1 bLCD_CTL(0x30) /* Frame buffer end address 1 (Background buffer 1) */ +#define LCDEADDRB2 bLCD_CTL(0x34) /* Frame buffer end address 2 (Background buffer 2) */ +#define LCDEADDRF1 bLCD_CTL(0x38) /* Frame buffer end address 1 (Foreground buffer 1) */ +#define LCDEADDRF3 bLCD_CTL(0x3c) /* Frame buffer end address 2 (Foreground buffer 2) */ +#define LCDVSCRB1 bLCD_CTL(0x40) /* Virture Screen OFFSIZE and PAGE WIDTH (Background buffer 1) */ +#define LCDVSCRB2 bLCD_CTL(0x44) /* Virture Screen OFFSIZE and PAGE WIDTH (Background buffer 2) */ +#define LCDVSCRF1 bLCD_CTL(0x48) /* Virture Screen OFFSIZE and PAGE WIDTH (Foreground buffer 1) */ +#define LCDVSCRF2 bLCD_CTL(0x4c) /* Virture Screen OFFSIZE and PAGE WIDTH (Foreground buffer 2) */ +#define LCDINTCON bLCD_CTL(0x50) /* LCD Interrupt Control */ +#define LCDKEYCON bLCD_CTL(0x54) /* COLOR KEY CONTROL 1 */ +#define LCDKEYVAL bLCD_CTL(0x58) /* COLOR KEY CONTROL 2 */ +#define LCDBGCON bLCD_CTL(0x5c) /* Background color Control */ +#define LCDFGCON bLCD_CTL(0x60) /* Foreground color Control */ +#define LCDDITHCON bLCD_CTL(0x64) /* LCD Dithering control active Matrix */ + +#define PALETTEBG 0x4A001000 //Background Palette start address +#define PALETTEFG 0x4A002000 //Background Palette start address + +/* LCDCON1 */ +#define fBURSTLEN Fld(2,28) /* DMA's BURST length selection*/ +#define BURSTLEN4 FInsrt(0x2, fBURSTLEN) +#define BURSTLEN8 FInsrt(0x1, fBURSTLEN) +#define BURSTLEN16 FInsrt(0x0, fBURSTLEN) +#define BDBCON_BUF1 (0 << 21) /* Active frame slect control background image */ +#define BDBCON_BUF2 (1 << 21) /* it will be adoted from next frame data */ +#define FDBCON_BUF1 (0 << 20) /* Active frame select control foreground image */ +#define FDBCON_BUF2 (1 << 20) /* it will adopted from next frame data */ +#define DIVEN (1 << 19) /* 1:ENABLE 0:Disable */ +#define DIVDIS (0 << 19) /* 0:disable */ +#define fCLKVAL Fld(6,13) +#define CLKVALMSK FMsk(fCLKVAL) /* clk value bit clear */ +#define CLKVAL(x) FInsrt((x), fCLKVAL) /* VCLK = HCLK / [(CLKVAL+1)x2] */ +#define CLKDIR_DIVIDE (1 << 12) /* Select the clk src as 0:direct or 1:divide using CLKVAl register*/ +#define CLKDIR_DIRECT (0 << 12) /* Select the clk src as 0:direct or 1:divide using CLKVAl register*/ +#define fPNRMODE Fld(2,9) /* Select Disaplay mode */ +#define PNRMODE_PRGB FInsrt(0x00, fPNRMODE) /* parallel RGB */ +#define PNRMODE_PBGR FInsrt(0x01, fPNRMODE) /* parallel BGR */ +#define PNRMODE_SRGB FInsrt(0x02, fPNRMODE) /* Serial RGB */ +#define PNRMODE_SBGR FInsrt(0x03, fPNRMODE) /* Serial RGB */ +#define fBPPMODEF Fld(3,6) /* SELECT THE BPP MODE FOR FOREGROUND IMAGE (OSD)*/ +#define BPPMODEF_8_P FInsrt(0x3, fBPPMODEF) /* 8BPP palettized */ +#define BPPMODEF_8_NP FInsrt(0x4, fBPPMODEF) /* 8BPP non palettized RGB-3:3:2 */ +#define BPPMODEF_565 FInsrt(0x5, fBPPMODEF) /* 16BPP NON palettized RGB-5:6:5 */ +#define BPPMODEF_5551 FInsrt(0x6, fBPPMODEF) /* 16BPP NON palettized RGB-5:5:5:1*/ +#define BPPMODEF_18_UP FInsrt(0x7, fBPPMODEF) /* unpaked 18BPP non-palettized */ +#define fBPPMODEB Fld(4,2) /* select the BPP mode for fore ground image*/ +#define MPPMODEB_1 FInsrt(0x00, fBPPMODEB) /* 1bpp */ +#define MPPMODEB_2 FInsrt(0x01, fBPPMODEB) /* 2bpp */ +#define MPPMODEB_4 FInsrt(0x02, fBPPMODEB) /* 4bpp */ +#define MPPMODEB_8 FInsrt(0x03, fBPPMODEB) /* 8bpp palettized */ +#define MPPMODEB_8N FInsrt(0x04, fBPPMODEB) /* 8bpp non palettized 3:3:2*/ +#define MPPMODEB_565 FInsrt(0x05, fBPPMODEB) /* 16bpp non palettized 5:6:5*/ +#define MPPMODEB_5551 FInsrt(0x06, fBPPMODEB) /* 16bpp non palettized 5:5:5:1*/ +#define MPPMODEB_18 FInsrt(0x07, fBPPMODEB) /* unpacked 18bpp */ +#define ENVID (1 << 1) /* 0:Disable 1:Enable LCD video output and logic immediatly */ +#define ENVID_F (1 << 0) /* 0:Dis 1:Ena wait until Current frame end. */ + +/* LCDCON2 */ +#define fPALFRM Fld(2,9) /* this bit determines the size of the palette data*/ +#define PALFRM_666 FInsrt(0x01, fPALFRM) /* 18 BIT RGB-6:6:6 */ +#define PALFRM_565 FInsrt(0x02, fPALFRM) /* 16 BIT RGB-5:6:5 */ +#define PALFRM_5551 FInsrt(0x03, fPALFRM) /* 16 BIT RGB-5:5:5:1 */ +#define IVCLK_RISING (1 << 7) /* this bit controls the polarity of the VCLK active edge */ +#define IVCLK_FALLING (0 << 7) /* 1 :rising edge 0: falling edge */ +#define IHSYNC_INVERT (1 << 6) /* HSYNC polarity inverted */ +#define IHSYNC_NORMAL (0 << 6) /* HSYNC polarity normal */ +#define IVSYNC_INVERT (1 << 5) /* VSYNC polarity inverted */ +#define IVSYNC_NORMAL (0 << 5) /* VSYNC polarity normal */ +#define IVDE_INVERT (1 << 3) /* DE polarity inverted */ +#define IVDE_NORMAL (0 << 3) /* DE polarity normal */ +#define BITSWP_EN (1 << 2) /* 1:BIT Swap Enable */ +#define BITSWP_DIS (0 << 2) /* 0:BIT Swap Disable */ +#define BYTESWP_EN (1 << 1) /* 1:BYTE Swap Enable */ +#define BUTESWP_DIS (0 << 1) /* 0:BYTE Swap Disable */ +#define HAWSWP_EN (1 << 0) /* 1:HALF WORD Swap Enable */ +#define HAWSWP_DIS (0 << 0) /* 0:HALF WORD swap Disable */ + +/* LCD Time Control 1 Register */ +#define VBPD(x) FInsrt((x), Fld(8,16)) /* VSync Back porch */ +#define VFPD(x) FInsrt((x), Fld(8, 8)) /* VSync Front porch */ +#define VSPW(x) FInsrt((x), Fld(8, 0)) /* VSync level width */ +/* LCD Time Control 2 Register */ +#define HBPD(x) FInsrt((x), Fld(8,16)) /* VSync Back porch */ +#define HFPD(x) FInsrt((x), Fld(8, 8)) /* VSync Front porch */ +#define HSPW(x) FInsrt((x), Fld(8, 0)) /* VSync level width */ +/* LCD Time Control 3 register */ +#define LINEVAL(x) FInsrt((x), Fld(11,11)) /* these bits determine the vertical size of lcd panel */ +#define HOZVAL(x) FInsrt((x), Fld(11, 0)) /* these bits determine the horizontal size of lcd panel*//* LCD OSD Control 1 register */ +#define OSDEN (1 << 9) /* OSD Enable */ +#define OSDDIS (0 << 9) /* OSD Disable */ +#define OSD_BLD_PIX (1 << 8) /* BLENDING MODE Per pixel blending (18 BPP only) */ +#define OSD_BLD_PLANE (0 << 8) /* Per plane blending (8/16/18 BPP mode) */ +#define OSD_ALPHA(x) FInsrt((x), Fld(8,0)) /* 8-bit Alpha value for Per plane defined by Equation 28-1. */ +/* LCD OSD Control 2 Register */ +#define OSD_LEFTTOP_X(x) FInsrt((x), Fld(11,11)) /*Horizontal screen coordinate for left top pixel of OSD image*/ +#define OSD_LEFTTOP_Y(x) FInsrt((y), Fld(11, 0)) /* Vertical screen coordinate for left top pixel of OSD image*/ +/* LCD OSD Control 3 Register */ +/*OSD_RIGHTBOT_X,_Y <= LCD Panel size of X, Y */ +#define OSD_RIGHTBOT_X(x) FInsrt((x), Fld(11,11)) /*Hor scr coordinate for right bottom pixel of OSD image. */ +#define OSD_RIGHTBOT_Y(y) FInsrt((y), Fld(11, 0)) /* Ver scr coordinate for right bottom pixel of OSD image.*/ +/* FRAME Buffer start address Register + LCDSADDRB1 Frame buffer start address register for Background buffer 1 + LCDSADDRB2 Frame buffer start address register for Background buffer 2 + LCDSADDRF1 Frame buffer start address register for Foreground(OSD) buffer 1 + LCDSADDRF2 Frame buffer start address register for Foreground(OSD) buffer 2*/ +#define LCDBANK(x) FInsrt((x), Fld( 8,24)) /* the bank location for the video buffer in the system memory. */ +#define LCDBASEU(x) FInsrt((x), Fld(24, 0)) /* the start address of the LCD frame buffer. */ +/* FRAME BUFFER END address Register + LCDEADDRB1 Frame buffer end address register for Background buffer 1 + LCDEADDRB2 Frame buffer end address register for Background buffer 2 + LCDEADDRF1 Frame buffer end address register for Foreground(OSD) buffer 1 + LCDEADDRF2 Frame buffer end address register for Foreground(OSD) buffer 2 + + LCDBASEL = LCDBASEU + (PAGEWIDTH+OFFSIZE) x (LINEVAL+1) */ +#define LCDBASEL(x) FInsrt((x), Fld(24,0)) /* the end address of the LCD frame buffer. */ +/* Virture Screen offsize and page width registers + LCDVSCRB1 Virtual screen OFFSIZE and PAGEWIDTH for Background buffer 1 + LCDVSCRB2 Virtual screen OFFSIZE and PAGEWIDTH for Background buffer 2 + LCDVSCRF1 Virtual screen OFFSIZE and PAGEWIDTH for Foreground(OSD) buffer 1 + LCDVSCRF2 Virtual screen OFFSIZE and PAGEWIDTH for Foreground(OSD) buffer 2*/ +#define OFFSIZE(x) FInsrt((x), Fld(13,13)) /* Virtual screen offset size (the number of byte). */ +#define PAGEWIDTH(x) FInsrt((x), Fld(13, 0)) /* Virtual screen page width (the number of byte). */ +/* LCD Interrupt Control Register */ +#define fFRAME_INT2 Fld(2,10) /* LCD Frame Interrupt 2 at start of */ +#define FRAMESEL0_BP FInsrt(0x0, fFRAME_INT2) /* BACK Porch */ +#define FRAMESEL0_VS FInsrt(0x1, fFRAME_INT2) /* VSYNC */ +#define FRAMESEL0_ACT FInsrt(0x2, fFRAME_INT2) /* ACTIVE */ +#define FRAMESEL0_FP FInsrt(0x3, fFRAME_INT2) /* FRONT */ +#define fFRAME_INT1 Fld(2,8) /* LCD Frame Interrupt 1 at start of */ +#define FRAMESEL1_BP FInsrt(0x1, fFRAME_INT1) /* BACK Porch */ +#define FRAMESEL1_VS FInsrt(0x2, fFRAME_INT1) /* VSYNC */ +#define FRAMESEL1_FP FInsrt(0x3, fFRAME_INT1) /* FRONTPorch */ +#define INTFRAME_EN (1 << 7) /* LCD Frame interrupt Enable */ +#define INTFRAME_DIS (0 << 7) /* LCD Frame interrupt Disable */ +#define fFIFOSEL Fld(2,5) /* LCD FIFO INTERRUPT SELECT BIT */ +#define FIFO_ALL FInsrt(0x00, fFIFOSEL) /* All fifi or CASE */ +#define FIFO_BG FInsrt(0x01, fFIFOSEL) /* Background only */ +#define FIFO_FG FInsrt(0x02, fFIFOSEL) /* FOREGROUND FIFO ONLY */ +#define fFIFOLEVEL Fld(3,2) /* LCD FIFO interrupt level select 1~128 word */ +#define FIFO_32W FInsrt(0x00, fFIFOLEVEL) /* 32 WORD LEFT */ +#define FIFO_64W FInsrt(0x01, fFIFOLEVEL) /* 64 WORD */ +#define FIFO_96W FInsrt(0x02, fFIFOLEVEL) /* 96 WORD */ +#define FIFO_OR FInsrt(0x03, fFIFOLEVEL) /* 32,64,96 WORD */ +#define INTFIFO_EN (1<<1) +#define INTFIFO_DIS (1<<1) +#define LCD_INTEN (1 << 0) /* LCD interrupt Enable */ +#define LCD_INTDIS (0 << 0) /* LCD Interrupt Disable */ +/* LCD color key LCDKEYCON 1 register */ +#define KEYEN (1 << 25) /* color key enable, blending disable */ +#define KEYDIS (0 << 25) /* color key disable, blending enable */ +#define DIRCON_FORE (1 << 24) /* pixel from foreground image is displayed (only in OSD area) */ +#define DIRCON_BACK (0 << 24) /* pixel from background image is displayed (only in OSD area) */ +#define COMPKEY(x) FInsrt((X), Fld(24,0)) /* Each bit is correspond to the COLVAL[23:0]. */ +/* color key 2 register LCDCOLVAL */ +#define COLVAL(x) FInsrt((x), Fld(24,0)) /* Color key value for the transparent pixel effect. */ +/* Background Color MAP */ +#define BGCOLEN (1 << 24) /* Background color mapping control bit enable */ +#define BGCOLDIS (0 << 24) /* Background color mapping control bit disable */ +#define BGCOLOR(x) FInsrt((x), Fld(24,0)) /* Color Value */ +/* Foreground Color MAP LCDFGCON */ +#define FGCOLEN (1 << 24) /* Foreground color mapping control bit Enable. */ +#define FGCOLDIS (0 << 24) /* Foreground color mapping control bit Disable */ +#define FGCOLOR(x) FInsrt((x), Fld(24,0)) /* Color Value */ +/* Dithering Contrl 1 Register LCD DITHERING MODE */ +#define RDITHPOS_6BIT FInsrt(0x01, Fld(2,5)) /* Red Dither bit control 6bit */ +#define RDITHPOS_5BIT FInsrt(0x02, Fld(2,5)) /* Red Dither bit control 5bit */ +#define GDITHPOS_6BIT FInsrt(0x01, Fld(2,3)) /* Green Dither bit control 6bit */ +#define GDITHPOS_5BIT FInsrt(0x02, Fld(2,3)) /* Green Dither bit control 5bit */ +#define BDITHPOS_6BIT FInsrt(0x01, Fld(2,5)) /* Blue Dither bit control 6bit */ +#define BDITHPOS_5BIT FInsrt(0x02, Fld(2,5)) /* Blue Dither bit control 5bit */ +#define DITHEN (1 << 0) /* Dithering Enable bit */ +#define DITHDIS (0 << 0) /* Dithering Disable bit */ + +#else +/* S3C24A0-X DEVICE ONLY */ +/* + * LCD (chapter 27 ) + */ +#define bLCD_CTL(Nb) __REG(0x4a000000 + (Nb)) +#define LCDCON1 bLCD_CTL(0x00) +#define LCDCON2 bLCD_CTL(0x04) +#define LCDCON3 bLCD_CTL(0x08) +#define LCDCON4 bLCD_CTL(0x0c) +#define LCDCON5 bLCD_CTL(0x10) +#define LCDADDR1 bLCD_CTL(0x14) +#define LCDADDR2 bLCD_CTL(0x18) +#define LCDADDR3 bLCD_CTL(0x1c) +#define TPAL bLCD_CTL(0x50) +#define LCDINTPND bLCD_CTL(0x54) +#define LCDSRCPND bLCD_CTL(0x58) +#define LCDINTMSK bLCD_CTL(0x5c) +#define OSD_SADDR bLCD_CTL(0x6c) +#define OSD_EADDR bLCD_CTL(0x70) +#define OSD_LT bLCD_CTL(0x74) /* left top */ +#define OSD_RB bLCD_CTL(0x78) /* right bottom & control */ +#define LCD_PAL bLCD_CTL(0x400) /* palette register */ + +#define fLCD1_LINECNT Fld(10,18) /* the status of the line counter */ +#define LCD1_LINECNT FMsk(fLCD_LINECNT) +#define fLCD1_CLKVAL Fld(10,8) /* rates of VCLK and CLKVAL[9:0] */ +#define LCD1_CLKVAL(x) FInsrt((x), fLCD1_CLKVAL) +#define LCD1_CLKVAL_MSK FMsk(fLCD1_CLKVAL) +#define fLCD1_PNR Fld(2,5) /* select the display mode */ +#define LCD1_PNR_TFT FInsrt(0x3, fLCD1_PNR) /* TFT LCD */ +#define fLCD1_BPP Fld(4,1) /* select BPP(Bit Per Pixel) */ +#define LCD1_BPP_1T FInsrt(0x8, fLCD1_BPP) /* TFT: 1 bpp */ +#define LCD1_BPP_2T FInsrt(0x9, fLCD1_BPP) /* TFT: 2 bpp */ +#define LCD1_BPP_4T FInsrt(0xa, fLCD1_BPP) /* TFT: 4 bpp */ +#define LCD1_BPP_8T FInsrt(0xb, fLCD1_BPP) /* TFT: 8 bpp */ +#define LCD1_BPP_16T FInsrt(0xc, fLCD1_BPP) /* TFT: 16 bpp */ +#define LCD1_ENVID (1 << 0) /* 1: Enable the video output */ +#define fLCD2_VBPD Fld(8,24) /* Vertical Back Porch */ +#define LCD2_VBPD(x) FInsrt(((x)-1), fLCD2_VBPD) +#define fLCD2_LINEVAL Fld(10,14) /* vertical size of LCD */ +#define LCD2_LINEVAL_MSK FMsk(fLCD2_LINEVAL) +#define LCD2_LINEVAL(x) FInsrt(((x)-1), fLCD2_LINEVAL) +#define fLCD2_VFPD Fld(8,6) /* Vertical Front Porch */ +#define LCD2_VFPD(x) FInsrt(((x)-1), fLCD2_VFPD) +#define fLCD2_VSPW Fld(6,0) /* Vertical Sync Pulse Width */ +#define LCD2_VSPW(x) FInsrt(((x)-1), fLCD2_VSPW) +#define fLCD3_HBPD Fld(7,19) /* Horizontal Back Porch */ +#define LCD3_HBPD(x) FInsrt(((x)-1), fLCD3_HBPD) +#define fLCD3_HOZVAL Fld(11,8) /* horizontal size of LCD */ +#define LCD3_HOZVAL_MSK FMsk(fLCD3_HOZVAL) +#define LCD3_HOZVAL(x) FInsrt(((x)-1), fLCD3_HOZVAL) +#define fLCD3_HFPD Fld(8,0) /* Horizontal Front Porch */ +#define LCD3_HFPD(x) FInsrt(((x)-1), fLCD3_HFPD) +#define fLCD4_HSPW Fld(8,0) /* Horizontal Sync Pulse Width */ +#define LCD4_HSPW(x) FInsrt(((x)-1), fLCD4_HSPW) +#define fLCD5_VSTAT Fld(2,15) /* Vertical Status (ReadOnly) */ +#define LCD5_VSTAT FMsk(fLCD5_VSTAT) +#define LCD5_VSTAT_VS 0x00 /* VSYNC */ +#define LCD5_VSTAT_BP 0x01 /* Back Porch */ +#define LCD5_VSTAT_AC 0x02 /* Active */ +#define LCD5_VSTAT_FP 0x03 /* Front Porch */ +#define fLCD5_HSTAT Fld(2,13) /* Horizontal Status (ReadOnly) */ +#define LCD5_HSTAT FMsk(fLCD5_HSTAT) +#define LCD5_HSTAT_HS 0x00 /* HSYNC */ +#define LCD5_HSTAT_BP 0x01 /* Back Porch */ +#define LCD5_HSTAT_AC 0x02 /* Active */ +#define LCD5_HSTAT_FP 0x03 /* Front Porch */ +#define LCD5_FRM565 (1 << 11) /* 1 : RGB 5:6:5 , 0 : RGB 5:5:5:1 */ +#define LCD5_INVVCL (1 << 10) /* + 1 : video data is fetched at VCLK falling edge + 0 : video data is fetched at VCLK rising edge */ +#define LCD5_HSYNC (1 << 9) /* 1: HSYNC pulse polarity is inverted */ +#define LCD5_VSYNC (1 << 8) /* 1: VSYNC pulse polarity is inverted */ +#define LCD5_INVVD (1 << 7) /* 1: VD pulse polarity is inverted */ +#define LCD5_INVVDEN (1 << 6) /* 1: VDEN signal polarity is inverted */ +#define LCD5_INVPWREN (1 << 5) /* 1: PWREN signal polarity is inverted */ +#define LCD5_INVLEND (1 << 4) /* 1: LEND signal polarity is inverted */ +#define LCD5_PWREN (1 << 3) /* 1: enable PWREN signal */ +#define LCD5_LEND (1 << 2) /* 1: enable LEND signal */ +#define LCD5_BSWP (1 << 1) /* 1: Byte swap enable */ +#define LCD5_HWSWP (1 << 0) /* 1: HalfWord swap enable */ + +#define fLCDADDR_BANK Fld(9,21) /* bank location for video buffer */ +#define LCDADDR_BANK(x) FInsrt((x), fLCDADDR_BANK) +#define fLCDADDR_BASEU Fld(21,0) /* address of upper left corner */ +#define LCDADDR_BASEU(x) FInsrt((x), fLCDADDR_BASEU) +#define fLCDADDR_BASEL Fld(21,0) /* address of lower right corner */ +#define LCDADDR_BASEL(x) FInsrt((x), fLCDADDR_BASEL) +#define fLCDADDR_OFFSET Fld(11,11) /* Virtual screen offset size + (# of half words) */ +#define LCDADDR_OFFSET(x) FInsrt((x), fLCDADDR_OFFSET) +#define fLCDADDR_PAGE Fld(11,0) /* Virtual screen page width + (# of half words) */ +#define LCDADDR_PAGE(x) FInsrt((x), fLCDADDR_PAGE) + +#define TPAL_LEN (1 << 24) /* 1 : Temp. Pallete Register enable */ +#define fTPAL_VAL Fld(24,0) /* Temp. Pallete Register value */ +#define TPAL_VAL(x) FInsrt((x), fTPAL_VAL) +#define TPAL_VAL_RED(x) FInsrt((x), Fld(8,16)) +#define TPAL_VAL_GREEN(x) FInsrt((x), Fld(8,8)) +#define TPAL_VAL_BLUE(x) FInsrt((x), Fld(8,0)) + +#define fOSD_SADDR Fld(30,0) /* OSD DMA start address of A[30:1] */ +#define OSD_Saddr(x) FInsrt((x), fOSD_SADDR) +#define fOSD_EADDR Fld(30,0) /* OSD DMA end address of A[30:1] */ +#define OSD_Eaddr(x) FInsrt((x), fOSD_EADDR) +#define OSD_BLD (1<<24) /* 0: per plane blending */ +#define fOSD_ALPHA Fld(4,20) /* 4-bit alpha value */ +#define OSD_ALPHA(x) FInsrt((x), fOSD_ALPHA) +#define fOSD_LT_X Fld(10,10) /* left-top X */ +#define OSD_LT_X(x) FInsrt((x), fOSD_LT_X) +#define fOSD_LT_Y Fld(10,0) /* left-top Y */ +#define OSD_LT_Y(x) FInsrt((x), fOSD_LT_Y) +#define OSD_EN (1<<31) /* 1: enable OSD */ +#define fOSD_WIDTH Fld(11,20) /* OSD width . # of half words */ +#define OSD_WIDTH(x) FInsrt((x), fOSD_WIDTH) +#define fOSD_RB_X Fld(10,10) /* right bottom X */ +#define OSD_RB_X(x) FInsrt((x), fOSD_RB_X) +#define fOSD_RB_Y Fld(10,0) /* right bottom Y */ +#define OSD_RB_Y(x) FInsrt((x), fOSD_RB_Y) +#endif + +/* + * UART ( chapter 11 ) + */ +#define UART_CTL_BASE 0x44400000 +#define UART0_CTL_BASE UART_CTL_BASE +#define UART1_CTL_BASE (UART_CTL_BASE + 0x4000) +#define bUART(x, Nb) __REG(UART_CTL_BASE + (x)*0x4000 + (Nb)) +/* offset */ +#define oULCON 0x00 +#define oUCON 0x04 +#define oUFCON 0x08 +#define oUMCON 0x0c +#define oUTRSTAT 0x10 +#define oUERSTAT 0x14 +#define oUFSTAT 0x18 +#define oUMSTAT 0x1c +#define oUTXH 0x20 +#define oURXH 0x24 +#define oUBRDIV 0x28 +/* Registers */ +#define ULCON0 bUART(0, oULCON) +#define UCON0 bUART(0, oUCON) +#define UFCON0 bUART(0, oUFCON) +#define UMCON0 bUART(0, oUMCON) +#define UTRSTAT0 bUART(0, oUTRSTAT) +#define UERSTAT0 bUART(0, oUERSTAT) +#define UFSTAT0 bUART(0, oUFSTAT) +#define UMSTAT0 bUART(0, oUMSTAT) +#define UTXH0 bUART(0, oUTXH) +#define URXH0 bUART(0, oURXH) +#define UBRDIV0 bUART(0, oUBRDIV) +#define ULCON1 bUART(1, oULCON) +#define UCON1 bUART(1, oUCON) +#define UFCON1 bUART(1, oUFCON) +#define UMCON1 bUART(1, oUMCON) +#define UTRSTAT1 bUART(1, oUTRSTAT) +#define UERSTAT1 bUART(1, oUERSTAT) +#define UFSTAT1 bUART(1, oUFSTAT) +#define UMSTAT1 bUART(1, oUMSTAT) +#define UTXH1 bUART(1, oUTXH) +#define URXH1 bUART(1, oURXH) +#define UBRDIV1 bUART(1, oUBRDIV) +/* ... */ + +#define ULCON_IR (1 << 6) /* use Infra-Red mode */ +#define fULCON_PAR Fld(3,3) /* what parity mode? */ +#define ULCON_PAR FMsk(fULCON_PAR) +#define ULCON_PAR_NONE FInsrt(0x0, fULCON_PAR) /* No Parity */ +#define ULCON_PAR_ODD FInsrt(0x4, fULCON_PAR) /* Odd Parity */ +#define ULCON_PAR_EVEN FInsrt(0x5, fULCON_PAR) /* Even Parity */ +#define ULCON_PAR_1 FInsrt(0x6, fULCON_PAR) /* Parity force/checked as 1 */ +#define ULCON_PAR_0 FInsrt(0x7, fULCON_PAR) /* Parity force/checked as 0 */ +#define ULCON_STOP (1 << 2) /* The number of stop bits */ +#define ULCON_ONE_STOP (0 << 2) /* 1 stop bit */ +#define ULCON_TWO_STOP (1 << 2) /* 2 stop bit */ +#define fULCON_WL Fld(2, 0) /* word length */ +#define ULCON_WL FMsk(fULCON_WL) +#define ULCON_WL5 FInsrt(0x0, fULCON_WL) /* 5 bits */ +#define ULCON_WL6 FInsrt(0x1, fULCON_WL) /* 6 bits */ +#define ULCON_WL7 FInsrt(0x2, fULCON_WL) /* 7 bits */ +#define ULCON_WL8 FInsrt(0x3, fULCON_WL) /* 8 bits */ + +#define ULCON_CFGMASK (ULCON_IR | ULCON_PAR | ULCON_WL) + +#define UCON_CLK_SEL (1 << 10) /* select clock for UART */ +#define UCON_CLK_PCLK (0 << 10) /* PCLK for UART baud rate */ +#define UCON_CLK_UCLK (1 << 10) /* UCLK for UART baud rate */ +#define UCON_TX_INT_TYPE (1 << 9) /* TX Interrupt request type */ +#define UCON_TX_INT_PLS (0 << 9) /* Pulse */ +#define UCON_TX_INT_LVL (1 << 9) /* Level */ +#define UCON_RX_INT_TYPE (1 << 8) /* RX Interrupt request type */ +#define UCON_RX_INT_PLS (0 << 8) /* Pulse */ +#define UCON_RX_INT_LVL (1 << 8) /* Level */ +#define UCON_RX_TIMEOUT (1 << 7) /* RX timeout enable */ +#define UCON_RX_ERR_INT (1 << 6) /* RX error status interrupt enable */ +#define UCON_LOOPBACK (1 << 5) /* to enter the loop-back mode */ +#define UCON_BRK_SIG (1 << 4) /* to send a break during 1 frame time */ +#define fUCON_TX Fld(2,2) /* function to write Tx data to the buffer */ +#define UCON_TX FMsk(fUCON_TX) +#define UCON_TX_DIS FInsrt(0x0, fUCON_TX) /* Disable */ +#define UCON_TX_INT FInsrt(0x1, fUCON_TX) /* Interrupt or polling */ +#define UCON_TX_DMA02 FInsrt(0x2, fUCON_TX) /* DMA0,2 for UART0 */ +#define UCON_TX_DMA13 FInsrt(0x3, fUCON_TX) /* DMA1,3 for UART1 */ +#define fUCON_RX Fld(2,0) /* function to read Rx data from buffer */ +#define UCON_RX FMsk(fUCON_RX) +#define UCON_RX_DIS FInsrt(0x0, fUCON_RX) /* Disable */ +#define UCON_RX_INT FInsrt(0x1, fUCON_RX) /* Interrupt or polling */ +#define UCON_RX_DMA02 FInsrt(0x2, fUCON_RX) /* DMA0,2 for UART0 */ +#define UCON_RX_DMA13 FInsrt(0x3, fUCON_RX) /* DMA1,3 for UART1 */ + +#define fUFCON_TX_TR Fld(2,6) /* trigger level of transmit FIFO */ +#define UFCON_TX_TR FMsk(fUFCON_TX_TR) +#define UFCON_TX_TR0 FInsrt(0x0, fUFCON_TX_TR) /* Empty */ +#define UFCON_TX_TR16 FInsrt(0x1, fUFCON_TX_TR) /* 16-byte */ +#define UFCON_TX_TR32 FInsrt(0x2, fUFCON_TX_TR) /* 32-byte */ +#define UFCON_TX_TR48 FInsrt(0x3, fUFCON_TX_TR) /* 48-byte */ +#define fUFCON_RX_TR Fld(2,4) /* trigger level of receive FIFO */ +#define UFCON_RX_TR FMsk(fUFCON_RX_TR) +#define UFCON_RX_TR1 FInsrt(0x0, fUFCON_RX_TR) /* 1-byte */ +#define UFCON_RX_TR8 FInsrt(0x1, fUFCON_RX_TR) /* 8-byte */ +#define UFCON_RX_TR16 FInsrt(0x2, fUFCON_RX_TR) /* 16-byte */ +#define UFCON_RX_TR32 FInsrt(0x3, fUFCON_RX_TR) /* 32-byte */ +#define UFCON_TX_CLR (1 << 2) /* auto-cleared after resetting FIFO */ +#define UFCON_RX_CLR (1 << 1) /* auto-cleared after resetting FIFO */ +#define UFCON_FIFO_EN (1 << 0) /* FIFO Enable */ + +#define UMCON_AFC (1 << 4) /* Enable Auto Flow Control */ +#define UMCON_SEND (1 << 0) /* if no AFC, set nRTS 1:'L' 0:'H' level */ + +#define UTRSTAT_TR_EMP (1 << 2) /* 1: Transmitter buffer & + shifter register empty */ +#define UTRSTAT_TX_EMP (1 << 1) /* Transmit buffer reg. is empty */ +#define UTRSTAT_RX_RDY (1 << 0) /* Receive buffer reg. has data */ + +#define UERSTAT_OVERRUN (1 << 0) /* Overrun Error */ +#define UERSTAT_ERR_MASK UERSTAT_OVERRUN + +#define UFSTAT_TX_FULL (1 << 14) /* Transmit FIFO is full */ +#define fUFSTAT_TX_CNT Fld(6,8) /* Number of data in Tx FIFO */ +#define UFSTAT_TX_CNT FMsk(fUFSTAT_TX_CNT) +#define UFSTAT_RX_FULL (1 << 6) /* Receive FIFO is full */ +#define fUFSTAT_RX_CNT Fld(6,0) /* Number of data in Rx FIFO */ +#define UFSTAT_RX_CNT FMsk(fUFSTAT_RX_CNT) +#define UART1_TXFIFO_CNT() FExtr(UFSTAT1, fUFSTAT_TX_CNT) +#define UART1_RXFIFO_CNT() FExtr(UFSTAT1, fUFSTAT_RX_CNT) + +#define UMSTAT_dCTS (1 << 4) /* delta CTS */ +#define UMSTAT_CTS (1 << 0) /* CTS(Clear to Send) signal */ + +#define UTXH_DATA 0x000000FF /* Transmit data for UARTn */ +#define URXH_DATA 0x000000FF /* Receive data for UARTn */ +#define UBRDIVn 0x0000FFFF /* Baud rate division value (> 0) */ + +/* + * GPIO ( chapter 20 ) + */ +#define GPIO_CONL_NUM (2) +#define GPIO_CONM_NUM (1) +#define GPIO_CONU_NUM (0) +#define GPIO_CONL_BASE (0<<3) +#define GPIO_CONM_BASE (11<<3) +#define GPIO_CONU_BASE (19<<3) +#define GPIO_CONL (GPIO_CONL_NUM | GPIO_CONL_BASE) +#define GPIO_CONM (GPIO_CONM_NUM | GPIO_CONM_BASE) +#define GPIO_CONU (GPIO_CONU_NUM | GPIO_CONU_BASE) + +#define GPCON(x) __REG(0x44800000 + (x) * 0x4) +#define GPCONU __REG(0x44800000) +#define GPCONM __REG(0x44800004) +#define GPCONL __REG(0x44800008) +#define GPDAT __REG(0x4480000c) +#define GPUP __REG(0x44800010) +#define GPIO_OFS_SHIFT 0 +#define GPIO_CON_SHIFT 8 +#define GPIO_PULLUP_SHIFT 16 +#define GPIO_MODE_SHIFT 24 +#define GPIO_OFS_MASK 0x000000ff +#define GPIO_CON_MASK 0x0000ff00 +#define GPIO_PULLUP_MASK 0x00ff0000 +#define GPIO_MODE_MASK 0xff000000 +#define GPIO_MODE_IN (0 << GPIO_MODE_SHIFT) +#define GPIO_MODE_OUT (1 << GPIO_MODE_SHIFT) +#define GPIO_MODE_ALT0 (2 << GPIO_MODE_SHIFT) +#define GPIO_MODE_ALT1 (3 << GPIO_MODE_SHIFT) +#define GPIO_PULLUP_EN (0 << GPIO_PULLUP_SHIFT) +#define GPIO_PULLUP_DIS (1 << GPIO_PULLUP_SHIFT) + +#define MAKE_GPIO_NUM(c, o) ((c << GPIO_CON_SHIFT) | (o << GPIO_OFS_SHIFT)) + +#define GRAB_MODE(x) (((x) & GPIO_MODE_MASK) >> GPIO_MODE_SHIFT) +#define GRAB_PULLUP(x) (((x) & GPIO_PULLUP_MASK) >> GPIO_PULLUP_SHIFT) +#define GRAB_OFS(x) (((x) & GPIO_OFS_MASK) >> GPIO_OFS_SHIFT) +#define GRAB_CON_NUM(x) ((((x) & GPIO_CON_MASK) >> GPIO_CON_SHIFT) & 0x07) +#define GRAB_CON_OFS(x) (GRAB_OFS(x) - (((x) & GPIO_CON_MASK) >> (GPIO_CON_SHIFT+3))) + +#define GPIO_0 MAKE_GPIO_NUM(GPIO_CONL, 0) +#define GPIO_1 MAKE_GPIO_NUM(GPIO_CONL, 1) +#define GPIO_2 MAKE_GPIO_NUM(GPIO_CONL, 2) +#define GPIO_3 MAKE_GPIO_NUM(GPIO_CONL, 3) +#define GPIO_4 MAKE_GPIO_NUM(GPIO_CONL, 4) +#define GPIO_5 MAKE_GPIO_NUM(GPIO_CONL, 5) +#define GPIO_6 MAKE_GPIO_NUM(GPIO_CONL, 6) +#define GPIO_7 MAKE_GPIO_NUM(GPIO_CONL, 7) +#define GPIO_8 MAKE_GPIO_NUM(GPIO_CONL, 8) +#define GPIO_9 MAKE_GPIO_NUM(GPIO_CONL, 9) +#define GPIO_10 MAKE_GPIO_NUM(GPIO_CONL, 10) +#define GPIO_11 MAKE_GPIO_NUM(GPIO_CONM, 11) +#define GPIO_12 MAKE_GPIO_NUM(GPIO_CONM, 12) +#define GPIO_13 MAKE_GPIO_NUM(GPIO_CONM, 13) +#define GPIO_14 MAKE_GPIO_NUM(GPIO_CONM, 14) +#define GPIO_15 MAKE_GPIO_NUM(GPIO_CONM, 15) +#define GPIO_16 MAKE_GPIO_NUM(GPIO_CONM, 16) +#define GPIO_17 MAKE_GPIO_NUM(GPIO_CONM, 17) +#define GPIO_18 MAKE_GPIO_NUM(GPIO_CONM, 18) +#define GPIO_19 MAKE_GPIO_NUM(GPIO_CONU, 19) +#define GPIO_20 MAKE_GPIO_NUM(GPIO_CONU, 20) +#define GPIO_21 MAKE_GPIO_NUM(GPIO_CONU, 21) +#define GPIO_22 MAKE_GPIO_NUM(GPIO_CONU, 22) +#define GPIO_23 MAKE_GPIO_NUM(GPIO_CONU, 23) +#define GPIO_24 MAKE_GPIO_NUM(GPIO_CONU, 24) +#define GPIO_25 MAKE_GPIO_NUM(GPIO_CONU, 25) +#define GPIO_26 MAKE_GPIO_NUM(GPIO_CONU, 26) +#define GPIO_27 MAKE_GPIO_NUM(GPIO_CONU, 27) +#define GPIO_28 MAKE_GPIO_NUM(GPIO_CONU, 28) +#define GPIO_29 MAKE_GPIO_NUM(GPIO_CONU, 29) +#define GPIO_30 MAKE_GPIO_NUM(GPIO_CONU, 30) +#define GPIO_31 MAKE_GPIO_NUM(GPIO_CONU, 31) +/* major alt. */ +#define GPIO_MODE_EINT GPIO_MODE_ALT0 +#define GPIO_MODE_RTC_ALARMINT GPIO_MODE_ALT1 +#define GPIO_MODE_IrDA GPIO_MODE_ALT1 +#define GPIO_MODE_PWM GPIO_MODE_ALT0 +#define GPIO_MODE_SPI GPIO_MODE_ALT1 +#define GPIO_MODE_EXT_DMA GPIO_MODE_ALT0 +#define GPIO_MODE_EXT_KEYP GPIO_MODE_ALT1 +#define GPIO_MODE_UART GPIO_MODE_ALT0 +/* canonical */ +#define GPIO_MODE_IrDA_SDBW GPIO_MODE_IrDA +#define GPIO_MODE_IrDA_TXD GPIO_MODE_IrDA +#define GPIO_MODE_IrDA_RXD GPIO_MODE_IrDA +#define GPIO_MODE_PWM_ECLK GPIO_MODE_PWM +#define GPIO_MODE_PWM_TOUT GPIO_MODE_PWM +#define GPIO_MODE_PWM_TOUT0 GPIO_MODE_PWM +#define GPIO_MODE_PWM_TOUT1 GPIO_MODE_PWM +#define GPIO_MODE_PWM_TOUT2 GPIO_MODE_PWM +#define GPIO_MODE_PWM_TOUT3 GPIO_MODE_PWM +#define GPIO_MODE_SPI_MODI GPIO_MODE_SPI +#define GPIO_MODE_SPI_MISO GPIO_MODE_SPI +#define GPIO_MODE_DMAREQ0 GPIO_MODE_EXT_DMA +#define GPIO_MODE_DMAREQ1 GPIO_MODE_EXT_DMA +#define GPIO_MODE_DMAACK0 GPIO_MODE_EXT_DMA +#define GPIO_MODE_DMAACK1 GPIO_MODE_EXT_DMA +#define GPIO_MODE_KEYP_ROW0 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_ROW1 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_ROW2 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_ROW3 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_ROW4 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_COL0 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_COL1 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_COL2 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_COL3 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_KEYP_COL4 GPIO_MODE_EXT_KEYP +#define GPIO_MODE_uCTSn1 GPIO_MODE_UART +#define GPIO_MODE_uRTSn1 GPIO_MODE_UART +#define GPIO_MODE_uTXD1 GPIO_MODE_UART +#define GPIO_MODE_uRXD1 GPIO_MODE_UART + +#define ENPU __REG(0x44800040) /* normal port pullup in sleep */ +#define ENPU_EN __REG(0x44800064) /* ENPU enable */ +#define GPDAT_S __REG(0x44800048) /* GPDAT in sleep */ +#define GPDAT_SEN __REG(0x4480004c) /* GPDAT_S enable */ +#define GPUP_S __REG(0x44800050) /* GPUP in sleep */ +#define DATR0_S __REG(0x44800054) /* data in sleep */ +#define DATR1_S __REG(0x44800058) /* data in sleep */ +#define OEN0_S __REG(0x4480005c) /* output in sleep */ +#define OEN1_S __REG(0x44800060) /* output in sleep */ + +#define ALIVECON __REG(0x44800044) /* clock for alive mode in sleep */ +#define RSTCNT __REG(0x44800068) /* reset count for power settle-down */ + +#define set_gpio_ctrl(x) \ + ({ GPCON(GRAB_CON_NUM((x))) &= ~(0x3 << (GRAB_CON_OFS((x))*2)); \ + GPCON(GRAB_CON_NUM(x)) |= (GRAB_MODE(x) << (GRAB_CON_OFS((x))*2)); \ + GPUP &= ~(1 << GRAB_OFS((x))); \ + GPUP |= (GRAB_PULLUP((x)) << GRAB_OFS((x))); }) +#define read_gpio_bit(x) ((GPDAT & (1<> GRAB_OFS((x))) +#define write_gpio_bit(x, v) \ + ({ GPDAT &= ~(0x1 << GRAB_OFS((x))); \ + GPDAT |= ((v) << GRAB_OFS((x))); }) + +/* + * USB Host ( chapter 17 ) + * - OHCI 1.0 + * - USB 1.1 + */ +#define USB_OHCI_BASE __REG(0x41000000) + +/* + * SROM Bank (chapter 2) for CS8900A + */ +#define SROM_BW __REG(0x40c20000) +#define SROM_BC1 __REG(0x40c20008) + + +/* + * Interrupt ( chpater 6 ) + */ +#define SRCPND __REG(0x40200000) +#define INTMOD __REG(0x40200004) +#define INTMSK __REG(0x40200008) +#define PRIORITY __REG(0x4020000c) +#define INTPND __REG(0x40200010) +#define INTOFFSET __REG(0x40200014) +#define SUBSRCPND __REG(0x40200018) +#define INTSUBMSK __REG(0x4020001c) + +#define EINTMASK __REG(0x44800034) +#define EINTPEND __REG(0x44800038) + +#define EINTCR0 __REG(0x44800018) +#define EINTCR1 __REG(0x4480001c) +#define EINTCR2 __REG(0x44800020) + + +/* + * BUS Martrix + */ + +#define PRIORITY0 __REG(0x40ce0000) +#define PRIORITY1 __REG(0x40ce0004) +#define PRIORITY_S_FIX 0x0 +#define PRIORITY_I_FIX 0x2 + +/* + * Watchdog timer ( chapter 8 ) + */ +#define WTCON __REG(0x44100000) +#define WTDAT __REG(0x44100004) +#define WTCNT __REG(0x44100008) + +/* + * Real time clock ( chapter 10 ) + * + * Note: All RTC registers have to be accessed by byte unit + * using STRB and LDRB instructions or char type pointer (page on 10-4) + */ +#define RTCCON __REG(0x44200040) +#define TICNT __REG(0x44200044) +#define RTCALM __REG(0x44200050) +#define ALMSEC __REG(0x44200054) +#define ALMMIN __REG(0x44200058) +#define ALMHOUR __REG(0x4420005c) +#define ALMDATE __REG(0x44200060) +#define ALMMON __REG(0x44200064) +#define ALMYEAR __REG(0x44200068) +#define RTCRST __REG(0x4420006c) +#define BCDSEC __REG(0x44200070) +#define BCDMIN __REG(0x44200074) +#define BCDHOUR __REG(0x44200078) +#define BCDDATE __REG(0x4420007c) +#define BCDDAY __REG(0x44200080) +#define BCDMON __REG(0x44200084) +#define BCDYEAR __REG(0x44200088) + +/* Fields */ +#define fRTC_SEC Fld(7,0) +#define fRTC_MIN Fld(7,0) +#define fRTC_HOUR Fld(6,0) +#define fRTC_DATE Fld(6,0) +#define fRTC_DAY Fld(2,0) +#define fRTC_MON Fld(5,0) +#define fRTC_YEAR Fld(8,0) +/* Mask */ +#define Msk_RTCSEC FMsk(fRTC_SEC) +#define Msk_RTCMIN FMsk(fRTC_MIN) +#define Msk_RTCHOUR FMsk(fRTC_HOUR) +#define Msk_RTCDAY FMsk(fRTC_DAY) +#define Msk_RTCDATE FMsk(fRTC_DATE) +#define Msk_RTCMON FMsk(fRTC_MON) +#define Msk_RTCYEAR FMsk(fRTC_YEAR) +/* bits */ +#define RTCCON_EN (1 << 0) /* RTC Control Enable */ +#define RTCCON_CLKSEL (1 << 1) /* BCD clock as XTAL 1/2^25 clock */ +#define RTCCON_CNTSEL (1 << 2) /* 0: Merge BCD counters */ +#define RTCCON_CLKRST (1 << 3) /* RTC clock count reset */ + +/* Tick Time count register */ +#define RTCALM_GLOBAL (1 << 6) /* Global alarm enable */ +#define RTCALM_YEAR (1 << 5) /* Year alarm enable */ +#define RTCALM_MON (1 << 4) /* Month alarm enable */ +#define RTCALM_DAY (1 << 3) /* Day alarm enable */ +#define RTCALM_HOUR (1 << 2) /* Hour alarm enable */ +#define RTCALM_MIN (1 << 1) /* Minute alarm enable */ +#define RTCALM_SEC (1 << 0) /* Second alarm enable */ +#define RTCALM_EN (RTCALM_GLOBAL | RTCALM_YEAR | RTCALM_MON |\ + RTCALM_DAY | RTCALM_HOUR | RTCALM_MIN |\ + RTCALM_SEC) +#define RTCALM_DIS (~RTCALM_EN) + +/* ADC and Touch Screen Interface */ +#define ADC_CTL_BASE 0x45800000 +#define bADC_CTL(Nb) __REG(ADC_CTL_BASE + (Nb)) +// Registers +#define ADCCON bADC_CTL(0x00) // R/W, ADC control register +#define ADCTSC bADC_CTL(0x04) // R/W, ADC touch screen ctl reg +#define ADCDLY bADC_CTL(0x08) // R/W, ADC start or interval delay reg +#define ADCDAX bADC_CTL(0x0c) // R , ADC conversion data reg +#define ADCDAY bADC_CTL(0x10) // R , ADC conversion data reg +// ADCCON +#define fECFLG Fld(1, 15) // R , End of conversion flag +#define ECFLG_VAL FExtr(ADCCON, fECFLG) +#define CONV_PROCESS 0 +#define CONV_END 1 + +#define fPRSCEN Fld(1, 14) +#define PRSCEN_DIS FInsrt(0, fPRSCEN) +#define PRSCEN_EN FInsrt(1, fPRSCEN) + +#define fPRSCVL Fld(8, 6) +#define PRSCVL(x) FInsrt(x, fPRSCVL) + +#define fSEL_MUX Fld(3, 3) +#define ADC_IN_SEL(x) FInsrt(x, fSEL_MUX) +#define ADC_IN0 0 +#define ADC_IN1 1 +#define ADC_IN2 2 +#define ADC_IN3 3 +#define ADC_IN4 4 +#define ADC_IN5 5 +#define ADC_IN6 6 +#define ADC_IN7 7 + +#define fSTDBM Fld(1, 2) // Standby mode select +#define STDBM_NORMAL FInsrt(0, fSTDBM) +#define STDBM_STANDBY FInsrt(1, fSTDBM) + +#define fREAD_START Fld(1, 1) +#define READ_START_DIS FInsrt(0, fREAD_START) +#define READ_START_EN FInsrt(1, fREAD_START) + +#define fENABLE_START Fld(1, 0) +#define ENABLE_START_NOOP FInsrt(0, fENABLE_START) +#define ENABLE_START_START FInsrt(1, fENABLE_START) + +// ADCTSC +#define fYM_SEN Fld(1, 7) +#define YM_HIZ FInsrt(0, fYM_SEN) +#define YM_GND FInsrt(1, fYM_SEN) +#define fYP_SEN Fld(1, 6) +#define YP_EXTVLT FInsrt(0, fYP_SEN) +#define YP_AIN5 FInsrt(1, fYP_SEN) +#define fXM_SEN Fld(1, 5) +#define XM_HIZ FInsrt(0, fXM_SEN) +#define XM_GND FInsrt(1, fXM_SEN) +#define fXP_SEN Fld(1, 4) +#define XP_EXTVLT FInsrt(0, fXP_SEN) +#define XP_AIN7 FInsrt(1, fXP_SEN) +#define fPULL_UP Fld(1, 3) +#define XP_PULL_UP_EN FInsrt(0, fPULL_UP) +#define XP_PULL_UP_DIS FInsrt(1, fPULL_UP) +#define fAUTO_PST Fld(1, 2) +#define AUTO_PST_NORMAL FInsrt(0, fAUTO_PST) +#define AUTO_PST_AUTO FInsrt(1, fAUTO_PST) +#define fXY_PST Fld(2, 0) +#define XY_PST_NOOP FInsrt(0, fXY_PST) +#define XY_PST_X_POS FInsrt(1, fXY_PST) +#define XY_PST_Y_POS FInsrt(2, fXY_PST) +#define XY_PST_WAIT_INT FInsrt(3, fXY_PST) + +// ADC Conversion DATA Field, commons +#define fUPDOWN Fld(1, 15) +#define fDAT_AUTO_PST Fld(1, 14) +#define fDAT_XY_PST Fld(2, 12) +#define fPST_DATA Fld(10, 0) // PST : position + +#define PST_DAT_MSK 0x3FF +#define PST_DAT_VAL(x) (FExtr(x, fPST_DATA) & PST_DAT_MSK) +// ADCDAX +#define XPDATA PST_DAT_VAL(ADCDAX) +// ADCDAY +#define YPDATA PST_DAT_VAL(ADCDAY) + +/* + * IIS Bus Interface ( chapter 14 ) + */ +#define IISCON __REG(0x44700000) +#define IISMOD __REG(0x44700004) +#define IISPSR __REG(0x44700008) +#define IISFIFOC __REG(0x4470000c) +#define IISFIFOE __REG(0x44700010) + +#define IISCON_CH_RIGHT (1 << 8) /* Right channel */ +#define IISCON_CH_LEFT (0 << 8) /* Left channel */ +#define IISCON_TX_RDY (1 << 7) /* Transmit FIFO is ready(not empty) */ +#define IISCON_RX_RDY (1 << 6) /* Receive FIFO is ready (not full) */ +#define IISCON_TX_DMA (1 << 5) /* Transmit DMA service reqeust */ +#define IISCON_RX_DMA (1 << 4) /* Receive DMA service reqeust */ +#define IISCON_TX_IDLE (1 << 3) /* Transmit Channel idle */ +#define IISCON_RX_IDLE (1 << 2) /* Receive Channel idle */ +#define IISCON_PRESCALE (1 << 1) /* IIS Prescaler Enable */ +#define IISCON_EN (1 << 0) /* IIS enable(start) */ + +#define IISMOD_SEL_MA (0 << 8) /* Master mode + (IISLRCK, IISCLK are Output) */ +#define IISMOD_SEL_SL (1 << 8) /* Slave mode + (IISLRCK, IISCLK are Input) */ +#define fIISMOD_SEL_TR Fld(2, 6) /* Transmit/Receive mode */ +#define IISMOD_SEL_TR FMsk(fIISMOD_SEL_TR) +#define IISMOD_SEL_NO FInsrt(0x0, fIISMOD_SEL_TR) /* No Transfer */ +#define IISMOD_SEL_RX FInsrt(0x1, fIISMOD_SEL_TR) /* Receive */ +#define IISMOD_SEL_TX FInsrt(0x2, fIISMOD_SEL_TR) /* Transmit */ +#define IISMOD_SEL_BOTH FInsrt(0x3, fIISMOD_SEL_TR) /* Tx & Rx */ +#define IISMOD_CH_RIGHT (0 << 5) /* high for right channel */ +#define IISMOD_CH_LEFT (1 << 5) /* high for left channel */ +#define IISMOD_FMT_IIS (0 << 4) /* IIS-compatible format */ +#define IISMOD_FMT_MSB (1 << 4) /* MSB(left)-justified format */ +#define IISMOD_BIT_8 (0 << 3) /* Serial data bit/channel is 8 bit*/ +#define IISMOD_BIT_16 (1 << 3) /* Serial data bit/channel is 16 bit*/ +#define IISMOD_FREQ_256 (0 << 2) /* Master clock freq = 256 fs */ +#define IISMOD_FREQ_384 (1 << 2) /* Master clock freq = 384 fs */ +#define fIISMOD_SFREQ Fld(2, 0) /* Serial bit clock frequency */ +#define IISMOD_SFREQ FMsk(fIISMOD_SFREQ) /* fs = sampling frequency */ +#define IISMOD_SFREQ_16 FInsrt(0x0, fIISMOD_SFREQ) /* 16 fs */ +#define IISMOD_SFREQ_32 FInsrt(0x1, fIISMOD_SFREQ) /* 32 fs */ +#define IISMOD_SFREQ_48 FInsrt(0x2, fIISMOD_SFREQ) /* 48 fs */ + +#define fIISPSR_A Fld(5, 5) /* Prescaler Control A */ +#define IISPSR_A(x) FInsrt((x), fIISPSR_A) +#define fIISPSR_B Fld(5, 0) /* Prescaler Control B */ +#define IISPSR_B(x) FInsrt((x), fIISPSR_B) + +#define IISFCON_TX_NORM (0 << 15) /* Transmit FIFO access mode: normal */ +#define IISFCON_TX_DMA (1 << 15) /* Transmit FIFO access mode: DMA */ +#define IISFCON_RX_NORM (0 << 14) /* Receive FIFO access mode: normal */ +#define IISFCON_RX_DMA (1 << 14) /* Receive FIFO access mode: DMA */ +#define IISFCON_TX_EN (1 << 13) /* Transmit FIFO enable */ +#define IISFCON_RX_EN (1 << 12) /* Recevice FIFO enable */ +#define fIISFCON_TX_CNT Fld(6, 6) /* Tx FIFO data count (Read-Only) */ +#define IISFCON_TX_CNT FMsk(fIISFCON_TX_CNT) +#define fIISFCON_RX_CNT Fld(6, 0) /* Rx FIFO data count (Read-Only) */ +#define IISFCON_RX_CNT FMsk(fIISFCON_RX_CNT) + +/* + * DMA controller ( chapter 9 ) + */ +#define DMA_CTL_BASE 0x40400000 +#define bDMA_CTL(Nb,x) __REG(DMA_CTL_BASE + (0x100000*Nb) + (x)) +/* DMA channel 0 */ +#define DISRC0 bDMA_CTL(0, 0x00) +#define DISRCC0 bDMA_CTL(0, 0x04) +#define DIDST0 bDMA_CTL(0, 0x08) +#define DIDSTC0 bDMA_CTL(0, 0x0c) +#define DCON0 bDMA_CTL(0, 0x10) +#define DSTAT0 bDMA_CTL(0, 0x14) +#define DCSRC0 bDMA_CTL(0, 0x18) +#define DCDST0 bDMA_CTL(0, 0x1c) +#define DMTRIG0 bDMA_CTL(0, 0x20) +/* DMA channel 1 */ +#define DISRC1 bDMA_CTL(1, 0x00) +#define DISRCC1 bDMA_CTL(1, 0x04) +#define DIDST1 bDMA_CTL(1, 0x08) +#define DIDSTC1 bDMA_CTL(1, 0x0c) +#define DCON1 bDMA_CTL(1, 0x10) +#define DSTAT1 bDMA_CTL(1, 0x14) +#define DCSRC1 bDMA_CTL(1, 0x18) +#define DCDST1 bDMA_CTL(1, 0x1c) +#define DMTRIG1 bDMA_CTL(1, 0x20) +/* DMA channel 2 */ +#define DISRC2 bDMA_CTL(2, 0x00) +#define DISRCC2 bDMA_CTL(2, 0x04) +#define DIDST2 bDMA_CTL(2, 0x08) +#define DIDSTC2 bDMA_CTL(2, 0x0c) +#define DCON2 bDMA_CTL(2, 0x10) +#define DSTAT2 bDMA_CTL(2, 0x14) +#define DCSRC2 bDMA_CTL(2, 0x18) +#define DCDST2 bDMA_CTL(2, 0x1c) +#define DMTRIG2 bDMA_CTL(2, 0x20) +/* DMA channel 3 */ +#define DISRC3 bDMA_CTL(3, 0x00) +#define DISRCC3 bDMA_CTL(3, 0x04) +#define DIDST3 bDMA_CTL(3, 0x08) +#define DIDSTC3 bDMA_CTL(3, 0x0c) +#define DCON3 bDMA_CTL(3, 0x10) +#define DSTAT3 bDMA_CTL(3, 0x14) +#define DCSRC3 bDMA_CTL(3, 0x18) +#define DCDST3 bDMA_CTL(3, 0x1c) +#define DMTRIG3 bDMA_CTL(3, 0x20) + +/* DISRC, DIDST Control registers */ +#define fDMA_BASE_ADDR Fld(30, 0) /* base address of src/dst data */ +#define DMA_BASE_ADDR(x) FInsrt(x, fDMA_BASE_ADDR) +#define LOC_SRC (1 << 1) /* select the location of source */ +#define ON_AHB (LOC_SRC*0) +#define ON_APB (LOC_SRC*1) +#define ADDR_MODE (1 << 0) /* select the address increment */ +#define ADDR_INC (ADDR_MODE*0) +#define ADDR_FIX (ADDR_MODE*1) + +/* DCON Definitions */ +#define DCON_MODE (1 << 31) /* 0: demand, 1: handshake */ +#define DEMAND_MODE (DCON_MODE*0) +#define HS_MODE (DCON_MODE*1) +#define DCON_SYNC (1 << 30) /* sync to 0:PCLK, 1:HCLK */ +#define SYNC_PCLK (DCON_SYNC*0) +#define SYNC_HCLK (DCON_SYNC*1) +#define DCON_INT (1 << 29) +#define POLLING_MODE (DCON_INT*0) +#define INT_MODE (DCON_INT*1) +#define DCON_TSZ (1 << 28) /* tx size 0: a unit, 1: burst */ +#define TSZ_UNIT (DCON_TSZ*0) +#define TSZ_BURST (DCON_TSZ*1) +#define DCON_SERVMODE (1 << 27) /* 0: single, 1: whole service */ +#define SINGLE_SERVICE (DCON_SERVMODE*0) +#define WHOLE_SERVICE (DCON_SERVMODE*1) +#define fDCON_HWSRC Fld(3, 24) /* select request source */ +#define CH0_nXDREQ0 0 +#define CH0_UART0 1 +#define CH0_I2SSDI 2 +#define CH0_TIMER 3 +#define CH0_USBEP1 4 +#define CH0_AC97_PCMOUT 5 +#define CH0_MSTICK 6 +#define CH0_IRDA 7 +#define CH1_nXDREQ1 0 +#define CH1_UART1 1 +#define CH1_I2SSDO 2 +#define CH1_SPI 3 +#define CH1_USBEP2 4 +#define CH1_AC97_PCMIN 5 +#define CH1_AC97_PCMOUT 6 +#define CH1_IRDA 7 +#define CH2_UART0 0 +#define CH2_I2SSDO 1 +#define CH2_SDMMC 2 +#define CH2_TIMER 3 +#define CH2_USBEP3 4 +#define CH2_AC97_MICIN 5 +#define CH2_AC97_PCMIN 6 +#define CH3_UART1 0 +#define CH3_SDMMC 1 +#define CH3_SPI 2 +#define CH3_TIMER 3 +#define CH3_USBEP4 4 +#define CH3_MSTICK 5 +#define CH3_AC97_MICIN 6 +#define HWSRC(x) FInsrt(x, fDCON_HWSRC) +#define DCON_SWHW_SEL (1 << 23) /* DMA src 0: s/w 1: h/w */ +#define DMA_SRC_SW (DCON_SWHW_SEL*0) +#define DMA_SRC_HW (DCON_SWHW_SEL*1) +#define DCON_RELOAD (1 << 22) /* set auto-reload */ +#define SET_ATRELOAD (DCON_RELOAD*0) +#define CLR_ATRELOAD (DCON_RELOAD*1) +#define fDCON_DSZ Fld(2, 20) +#define DSZ_BYTE 0 +#define DSZ_HALFWORD 1 +#define DSZ_WORD 2 +#define DSZ(x) FInsrt(x, fDCON_DSZ) +#define readDSZ(x) FExtr(x, fDCON_DSZ) +#define fDCON_TC Fld(20,0) +#define TX_CNT(x) FInsrt(x, fDCON_TC) +/* STATUS Register Definitions */ +#define fDSTAT_ST Fld(2,20) /* Status of DMA Controller */ +#define fDSTAT_TC Fld(20,0) /* Current value of transfer count */ +#define DMA_STATUS(chan) FExtr((DSTAT0 + (0x20 * chan)), fDSTAT_ST) +#define DMA_BUSY (1 << 0) +#define DMA_READY (0 << 0) +#define DMA_CURR_TC(chan) FExtr((DSTAT0 + (0x20 * chan)), fDSTAT_TC) +/* DMA Trigger Register Definitions */ +#define DMASKTRIG_STOP (1 << 2) /* Stop the DMA operation */ +#define DMA_STOP (DMASKTRIG_STOP*1) +#define DMA_STOP_CLR (DMASKTRIG_STOP*0) +#define DMASKTRIG_ONOFF (1 << 1) /* DMA channel on/off */ +#define CHANNEL_ON (DMASKTRIG_ONOFF*1) +#define CHANNEL_OFF (DMASKTRIG_ONOFF*0) +#define DMASKTRIG_SW (1 << 0) /* Trigger DMA ch. in S/W req. mode */ +#define DMA_SW_REQ_CLR (DMASKTRIG_SW*0) +#define DMA_SW_REQ (DMASKTRIG_SW*1) + +/* + * KeyIF - keypad interface + * chapter 28 + */ +#define KEYDAT __REG(0x44900000) +#define KEYINTC __REG(0x44900004) +#define KEYFLT0 __REG(0x44900008) +#define KEYFLT1 __REG(0x4490000C) +#define fKEYDAT_KEYS Fld(5,0) /* RO : intput decoding data */ +#define KEYDAT_KEYS FExtr(KEYDAT, fKEYDAT_KEYS) +#define KEYDAT_KEYVAL (1<<5) /* RO : 0=valid, 1=invalid */ +#define KEYDAT_KEYCLR (1<<6) /* WO : 0=noaction, 1=clear */ +#define KEYDAT_KEYEN (1<<7) /* RW : 0=disable, 1=enable */ +#define fKEYINTLV Fld(3,0) +#define KEYINTLV_LL 0 /* low level */ +#define KEYINTLV_HL 1 /* high level */ +#define KEYINTLV_RE 2 /* rising edge */ +#define KEYINTLV_FE 4 /* falling edge */ +#define KEYINTLV_BE 6 /* both edges */ +#define KEYINTLV(x) FInsrt((x), fKEYINTLV) +#define KEYINTEN (1<<3) /* interrupt enable */ +#define fKEYFLT_SELCLK Fld(1,0) +#define SELCLK_RTC 0 +#define SELCLK_GCLK 1 +#define KEYFLT_SELCLK(x) FInsrt((x),fKEYFLT_SELCLK) +#define KEYFLT_FILEN (1<<1) +#define fKEYFLT_WIDTH Fld( 14,0) +#define KEYFLT_WIDTH(x) FInsrt((x), fKEYFLT_WIDTH) +#define KEYP_STAT (((GPDAT & 0x00FF0000) >> 16 ) & 0x7D ) + +/* + * Video Post Processor ? + * + * chapter 26. + */ +#define VP_MODE __REG(0x4a100000) /* RW */ +#define VP_RATIO_Y __REG(0x4a100004) /* RW */ +#define VP_RATIO_CB __REG(0x4a100008) /* RW */ +#define VP_RATIO_CR __REG(0x4a10000c) /* RW */ +#define VP_SRC_WIDTH __REG(0x4a100010) /* RW */ +#define VP_SRC_HEIGHT __REG(0x4a100014) /* RW */ +#define VP_DST_WIDTH __REG(0x4a100018) /* RW */ +#define VP_DST_HEIGHT __REG(0x4a10001c) /* RW */ +#define VP_START_Y1 __REG(0x4a100020) /* RW */ +#define VP_START_Y2 __REG(0x4a100024) /* RW */ +#define VP_START_Y3 __REG(0x4a100028) /* RW */ +#define VP_START_Y4 __REG(0x4a10002c) /* RW */ +#define VP_START_CB1 __REG(0x4a100030) /* RW */ +#define VP_START_CB2 __REG(0x4a100034) /* RW */ +#define VP_START_CB3 __REG(0x4a100038) /* RW */ +#define VP_START_CB4 __REG(0x4a10003c) /* RW */ +#define VP_START_CR1 __REG(0x4a100040) /* RW */ +#define VP_START_CR2 __REG(0x4a100044) /* RW */ +#define VP_START_CR3 __REG(0x4a100048) /* RW */ +#define VP_START_CR4 __REG(0x4a10004c) /* RW */ +#define VP_START_RGB1 __REG(0x4a100050) /* RW */ +#define VP_START_RGB2 __REG(0x4a100054) /* RW */ +#define VP_START_RGB3 __REG(0x4a100058) /* RW */ +#define VP_START_RGB4 __REG(0x4a10005c) /* RW */ +#define VP_END_Y1 __REG(0x4a100060) /* RW */ +#define VP_END_Y2 __REG(0x4a100064) /* RW */ +#define VP_END_Y3 __REG(0x4a100068) /* RW */ +#define VP_END_Y4 __REG(0x4a10006c) /* RW */ +#define VP_END_CB1 __REG(0x4a100070) /* RW */ +#define VP_END_CB2 __REG(0x4a100074) /* RW */ +#define VP_END_CB3 __REG(0x4a100078) /* RW */ +#define VP_END_CB4 __REG(0x4a10007c) /* RW */ +#define VP_END_CR1 __REG(0x4a100080) /* RW */ +#define VP_END_CR2 __REG(0x4a100084) /* RW */ +#define VP_END_CR3 __REG(0x4a100088) /* RW */ +#define VP_END_CR4 __REG(0x4a10008c) /* RW */ +#define VP_END_RGB1 __REG(0x4a100090) /* RW */ +#define VP_END_RGB2 __REG(0x4a100094) /* RW */ +#define VP_END_RGB3 __REG(0x4a100098) /* RW */ +#define VP_END_RGB4 __REG(0x4a10009c) /* RW */ +#define VP_BYPASS __REG(0x4a1000f0) /* RW */ +#define VP_OFS_Y __REG(0x4a1000f4) /* RW */ +#define VP_OFS_CB __REG(0x4a1000f8) /* RW */ +#define VP_OFS_CR __REG(0x4a1000fc) /* RW */ +#define VP_OFS_RGB __REG(0x4a100100) /* RW */ + +#define VP_STY(__x) __REG(0x4a100020 + 4*(__x)) +#define VP_STCB(__x) __REG(0x4a100030 + 4*(__x)) +#define VP_STCR(__x) __REG(0x4a100040 + 4*(__x)) +#define VP_STRGB(__x) __REG(0x4a100050 + 4*(__x)) +#define VP_EDY(__x) __REG(0x4a100060 + 4*(__x)) +#define VP_EDCB(__x) __REG(0x4a100070 + 4*(__x)) +#define VP_EDCR(__x) __REG(0x4a100080 + 4*(__x)) +#define VP_EDRGB(__x) __REG(0x4a100090 + 4*(__x)) + +#define fVP_MODE_FRMCNT Fld(2,10) +#define VP_MODE_FRMCNT(x) FExtr((x), fVP_MODE_FRMCNT) +#define VP_MODE_BYPASSFC (1<<9) +#define VP_MODE_BYPASSCSC (1<<8) +#define VP_MODE_INT (1<<7) +#define VP_MODE_INTPND (1<<6) +#define VP_MODE_EN (1<<5) +#define VP_MODE_ORGB24 (1<<4) /* output : 0=RGB16(565) , 1=RGB24 */ +#define VP_MODE_IFMT (1<<3) /* input : 0=YUV , 1=RGB */ +#define VP_MODE_INTLV (1<<2) +#define VP_MODE_IRGB24 (1<<1) /* input : 0=RGB16(565) , 1=RGB24 */ +#define VP_MODE_IYUV (1<<0) /* if (VP_MODE_IFMT==0 && VP_MODE_INTLV==1) + 0=YUYV , 1=UYVY */ + +#define fVP_RATIO_V Fld(16,16) +#define fVP_RATIO_H Fld(16,0) +#define VP_RATIO_V(x) FInsrt((x), fVP_RATIO_V) +#define VP_RATIO_H(x) FInsrt((x), fVP_RATIO_H) + +#define fVP_IMG_SIZE_Y Fld(10,20) +#define fVP_IMG_SIZE_CB Fld(10,10) +#define fVP_IMG_SIZE_CR Fld(10,0) +#define VP_IMG_SIZE_Y(x) FInsrt((x), fVP_IMG_SIZE_Y) +#define VP_IMG_SIZE_CB(x) FInsrt((x), fVP_IMG_SIZE_CB) +#define VP_IMG_SIZE_CR(x) FInsrt((x), fVP_IMG_SIZE_CR) +#define VP_IMG_SIZE_R(x) FInsrt((x), fVP_IMG_SIZE_Y) +#define VP_IMG_SIZE_G(x) FInsrt((x), fVP_IMG_SIZE_CB) +#define VP_IMG_SIZE_B(x) FInsrt((x), fVP_IMG_SIZE_CR) +#define VP_SIZE_XX(__x) ((__x)-1) + +#define VP_BYPASS_EN (1<<24) +#define fVP_BYPASS_LOW Fld(12,12) +#define fVP_BYPASS_HIGH Fld(12,0) +#define VP_BYPASS_LOW(x) FInsrt((x), fVP_BYPASS_LOW) +#define VP_BYPASS_HIGH(x) FInsrt((x), fVP_BYPASS_HIGH) + + +/* + * IrDA Controller (Chapter 12) + */ +#define IRDACNT __REG(0x41800000) /* Control */ +#define IRDAMDR __REG(0x41800004) /* Mode definition */ +#define IRDACNF __REG(0x41800008) /* IRQ//DMA configuration */ +#define IRDAIER __REG(0x4180000c) /* IRQ enable */ +#define IRDAIIR __REG(0x41800010) /* IRQ indentification */ +#define IRDALSR __REG(0x41800014) /* Line status */ +#define IRDAFCR __REG(0x41800018) /* FIFO control */ +#define IRDAPRL __REG(0x4180001c) /* Preamble length */ +#define IRDARBR __REG(0x41800020) /* Tx/Rx Buffer */ +#define IRDATXNO __REG(0x41800024) /* Total number of data bytes remained in Tx FIFO */ +#define IRDARXNO __REG(0x41800028) /* Total number of data remained in Rx FIFO (in bytes) */ +#define IRDATXFLL __REG(0x4180002c) /* Tx frame length (Low) */ +#define IRDATXFLH __REG(0x41800030) /* Tx frame length (High) */ +#define IRDARXFLL __REG(0x41800034) /* Rx frame length (Low) */ +#define IRDARXFLH __REG(0x41800038) /* Rx frame length (High */ +#define IRDATIME __REG(0x4180003c) /* Timing control */ + +/* + * SPI Interface + */ +#define SPCON0 __REG(0x44500000) +#define SPSTA0 __REG(0x44500004) +#define SPPIN0 __REG(0x44500008) +#define SPPRE0 __REG(0x4450000C) +#define SPTDAT0 __REG(0x44500010) +#define SPRDAT0 __REG(0x44500014) +#define SPCON1 __REG(0x44500020) +#define SPSTA1 __REG(0x44500024) +#define SPPIN1 __REG(0x44500028) +#define SPPRE1 __REG(0x4450002C) +#define SPTDAT1 __REG(0x44500030) +#define SPRDAT1 __REG(0x44500034) + +#define fSPCON_SMOD Fld(2,5) /* SPI mode select */ +#define SPCON_SMOD FMsk(fSPCON_SMOD) +#define SPCON_SMOD_POLL FInsrt(0x0, fSPCON_SMOD) +#define SPCON_SMOD_INT FInsrt(0x1, fSPCON_SMOD) +#define SPCON_SMOD_DMA FInsrt(0x2, fSPCON_SMOD) +#define SPCON_ENSCK (1 << 4) +#define SPCON_MSTR (1 << 3) +#define SPCON_CPOL (1 << 2) +#define SPCON_CPOL_LOW (1 << 2) +#define SPCON_CPOL_HIGH (0 << 2) +#define SPCON_CPHA (1 << 1) +#define SPCON_CPHA_FMTA (0 << 1) +#define SPCON_CPHA_FMTB (1 << 1) +#define SPCON_TAGD (1 << 0) + +#define SPSTA_DCOL (1 << 2) /* Data Collision Error */ +#define SPSTA_MULF (1 << 1) /* Multi Master Error */ +#define SPSTA_READY (1 << 0) /* Data Tx/Rx ready */ + +/* + * IIC Controller (Chapter 13) + */ + +#define IICCON __REG(0x44600000) +#define IICSTAT __REG(0x44600004) +#define IICADD __REG(0x44600008) +#define IICDS __REG(0x4460000C) +#define IICADADLY __REG(0x44600010) + +/* + * Memory Stick Controller (Chapter 31) + */ +#define _MS_BASE0 0x46100000 +#define _MS_BASE1 0x46108000 +#define bMS_CTL0(x) __REG(_MS_BASE0 + (x)) +#define bMS_CTL1(x) __REG(_MS_BASE1 + 4*(x)) +#define MSPRE bMS_CTL0(0) /* Prescaler Control */ +#define MSFINTCON bMS_CTL0(4) /* FIFO Interrupt Control */ +#define MS_TP_CMD bMS_CTL1(0) /* Transfer Protocol Command */ +#define MS_CTRL_STA bMS_CTL1(1) /* Control1 and Status */ +#define MS_DAT bMS_CTL1(2) /* Data FIFO */ +#define MS_INT bMS_CTL1(3) /* Interrupt Control and Status */ +#define MS_INS bMS_CTL1(4) /* INS port Control and Status */ +#define MS_ACMD bMS_CTL1(5) /* Auto Command/Polarity Control */ +#define MS_ATP_CMD bMS_CTL1(6) /* Auto Transfer Protocol Command */ + +#define MSPRE_EN (1 << 2) /* Prescaler control, + 0:Disable, 1:Enable. */ +#define MSPRE_VAL (0x3 << 0) /* Prescaler value */ +#define MSPRE_VAL1 (0x0 << 0) /* 1/1 */ +#define MSPRE_VAL2 (0x1 << 0) /* 1/2 */ +#define MSPRE_VAL4 (0x2 << 0) /* 1/4 */ +#define MSPRE_VAL8 (0x3 << 0) /* 1/8 */ + +#define MSFINTCON_EN 0x1 /* FIFO interrupt control, + 0:only for XINT, + 1:FIFO interrupt enable */ + +#define MS_CTRL_RST (1 << 15) /* Internal logic reset */ +#define MS_CTRL_PWS (1 << 14) /* Power save mode */ +#define MS_CTRL_SIEN (1 << 13) /* Serial interface enable */ +#define MS_CTRL_NOCRC (1 << 11) /* INT_CRC disable */ +#define MS_CTRL_BSYCNT (0x7 << 8) /* Busy timeout count + timeout time = BSYCNT*4+2[pclks] */ +#define fMS_CTRL_BSYCNT Fld(3,8) +#define MS_CTRL_BSY(x) FInsrt((x), fMS_CTRL_BSYCNT) +#define MS_INT_STA (1 << 7) /* interrupt generated */ +#define MS_DRQ_STA (1 << 6) /* DMA requested */ +#define MS_RBE_STA (1 << 3) /* Receive buffer empty */ +#define MS_RBF_STA (1 << 2) /* Receive buffer full */ +#define MS_TBE_STA (1 << 1) /* Transmit buffer empty */ +#define MS_TBF_STA (1 << 0) /* Transmit buffer full */ + +#define MS_INT_EN (1 << 15) /* Memory stick Interrupt enable */ +#define MS_TR_INTEN (1 << 14) /* Data transfer interrupt enable */ +#define MS_INS_INTEN (1 << 13) /* Insertion interrupt enable */ +#define MS_INT_P_END (1 << 7) /* Protocol end interrupt status + 0 = In progress 1 = Complete */ +#define MS_INT_SIF (1 << 6) /* Serial interface receive INTd */ +#define MS_INT_TR (1 << 5) /* Data transfer request INTd */ +#define MS_INT_INS (1 << 4) /* Insertion INTd */ +#define MS_INT_CRC (1 << 1) /* INT_CRC error */ +#define MS_INT_TOE (1 << 0) /* BUSY timeout error */ + +#define MS_INS_EN (1 << 12) /* INS port enable */ +#define MS_INS_STA (1 << 4) /* INS port status. 1:Low(Insert) */ + +#define MS_ACMD_EN (1 << 15) /* Auto Command op. enable */ +#define MS_ACMD_RISING (0 << 14) /* serial data input is rising Edge */ +#define MS_ACMD_FALLING (1 << 14) /* serial data input is falling Edge */ + +/* + * Modem Interface (Chapter 19) + */ +#define INT2AP __REG(0x41180000) +#define INT2MDM __REG(0x41180004) + +#define fINT2AP_ADR Fld(11,0) /* IRQ to AP address */ +#define INT2AP_ADR FMsk(fINT2AP_ADR) +#define fINT2MDM_ADR Fld(11,0) /* IRQ to Modem address */ +#define INT2MDM_ADR FMsk(fINT2MDM_ADR) + +/* + * Power management + */ +#define ALIVECON __REG(0x44800044) +#define GPDATINSLEEP __REG(0x44800048) +#define ENGPINSLEEP __REG(0x4480004c) +#define GPUPINSLEEP __REG(0x44800050) +#define DATRINSLEEP0 __REG(0x44800054) +#define DATRINSLEEP1 __REG(0x44800058) +#define OENINSLEEP0 __REG(0x4480005c) +#define OENINSLEEP1 __REG(0x44800060) +#define ENPUINSLEEP __REG(0x44800064) +#define RSTCNT __REG(0x44800068) + +#endif /* _S3C24A0_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/bitfield.h b/include/asm-arm/arch-s3c24a0/bitfield.h new file mode 100644 index 00000000..0b7eceef --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/bitfield.h @@ -0,0 +1,116 @@ +/* + * FILE bitfield.h + * + * Version 1.1 + * Author Copyright (c) Marc A. Viredaz, 1998 + * DEC Western Research Laboratory, Palo Alto, CA + * Date April 1998 (April 1997) + * System Advanced RISC Machine (ARM) + * Language C or ARM Assembly + * Purpose Definition of macros to operate on bit fields. + */ + + + +#ifndef __BITFIELD_H +#define __BITFIELD_H + +#ifndef __ASSEMBLY__ +#define UData(Data) ((unsigned long) (Data)) +#else +#define UData(Data) (Data) +#endif + + +/* + * MACRO: Fld + * + * Purpose + * The macro "Fld" encodes a bit field, given its size and its shift value + * with respect to bit 0. + * + * Note + * A more intuitive way to encode bit fields would have been to use their + * mask. However, extracting size and shift value information from a bit + * field's mask is cumbersome and might break the assembler (255-character + * line-size limit). + * + * Input + * Size Size of the bit field, in number of bits. + * Shft Shift value of the bit field with respect to bit 0. + * + * Output + * Fld Encoded bit field. + */ + +#define Fld(Size, Shft) (((Size) << 16) + (Shft)) + + +/* + * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit + * + * Purpose + * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return + * the size, shift value, mask, aligned mask, and first bit of a + * bit field. + * + * Input + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FSize Size of the bit field, in number of bits. + * FShft Shift value of the bit field with respect to bit 0. + * FMsk Mask for the bit field. + * FAlnMsk Mask for the bit field, aligned on bit 0. + * F1stBit First bit of the bit field. + */ + +#define FSize(Field) ((Field) >> 16) +#define FShft(Field) ((Field) & 0x0000FFFF) +#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) +#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) +#define F1stBit(Field) (UData (1) << FShft (Field)) + +#define FClrBit(Data, Bit) (Data = (Data & ~(Bit))) +#define FClrFld(Data, Field) (Data = (Data & ~FMsk(Field))) + + +/* + * MACRO: FInsrt + * + * Purpose + * The macro "FInsrt" inserts a value into a bit field by shifting the + * former appropriately. + * + * Input + * Value Bit-field value. + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FInsrt Bit-field value positioned appropriately. + */ + +#define FInsrt(Value, Field) \ + (UData (Value) << FShft (Field)) + + +/* + * MACRO: FExtr + * + * Purpose + * The macro "FExtr" extracts the value of a bit field by masking and + * shifting it appropriately. + * + * Input + * Data Data containing the bit-field to be extracted. + * Field Encoded bit field (using the macro "Fld"). + * + * Output + * FExtr Bit-field value. + */ + +#define FExtr(Data, Field) \ + ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) + + +#endif /* __BITFIELD_H */ diff --git a/include/asm-arm/arch-s3c24a0/clocks.h b/include/asm-arm/arch-s3c24a0/clocks.h new file mode 100644 index 00000000..4ba8c6e0 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/clocks.h @@ -0,0 +1,38 @@ +/* + * include/asm-arm/arch-s3c24a0/clocks.h + * + * $Id: clocks.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * 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 + */ + +#ifndef _S3C24A0_CLOCK_H_ +#define _S3C24A0_CLOCK_H_ + +#include + +#define GET_PCLK 0 +#define GET_HCLK 1 +#define GET_UPLL 2 + +#define GET_MDIV(x) FExtr(x, fPLL_MDIV) +#define GET_PDIV(x) FExtr(x, fPLL_PDIV) +#define GET_SDIV(x) FExtr(x, fPLL_SDIV) + +#define get_cpu_clk() elfin_get_cpu_clk() +#define get_bus_clk(x) elfin_get_bus_clk((x)) + +unsigned long elfin_get_cpu_clk(void); +unsigned long elfin_get_bus_clk(int); +#endif /* _S3C24A0_CLOCK_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/debug-macro.S b/include/asm-arm/arch-s3c24a0/debug-macro.S new file mode 100644 index 00000000..c003cfd8 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/debug-macro.S @@ -0,0 +1,40 @@ +/* linux/include/asm-arm/arch-s3c24a0/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 2005 Hyok S. Choi + * + * 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. + * +*/ + + .macro addruart, rx + .endm + + .macro senduart,rd,rx + mov r1, #0x00000002 + MRC p14, 0, r3, c0, c0 ;read comms control reg + AND r3, r3, r1 + CMP r3, #2 + BEQ $-0x0C + CMP r0, #0x0a + BNE $+0x1C + mov r3, #0x0d + MCR p14, 0, r3, c1, c0 ;write comms data reg + MRC p14, 0, r3, c0, c0 ;read comms control reg + AND r3, r3, r1 + CMP r3, #2 + BEQ $-0x0C + MCR p14, 0, r0, c1, c0 ;write comms data reg + mov pc,r14 + .endm + + .macro busyuart, rd, rx + .endm + + .macro waituart,rd,rx + .endm + + diff --git a/include/asm-arm/arch-s3c24a0/dma.h b/include/asm-arm/arch-s3c24a0/dma.h new file mode 100644 index 00000000..c390eadf --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/dma.h @@ -0,0 +1,55 @@ +/* + * include/asm-arm/arch-s3c24a0/dma.h + * + * $Id: dma.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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 linux/include/asm-arm/arch-s3c2410/dma.h + * + */ + +#ifndef __ASM_ARCH_DMA_H__ +#define __ASM_ARCH_DMA_H__ + +#include "hardware.h" + +#define MAX_DMA_ADDRESS 0xffffffff + +/* + * NB: By nandy + * If MAX_DMA_CHANNELS is zero, It means that this architecuture not use + * the regular generic DMA interface provided by kernel. + * Why? I don't know. I will investigate S3C24A0 DMA model and generic + * DMA interface. But not yet. + */ +#define MAX_DMA_CHANNELS 0 + +/* The S3C24A0 has four internal DMA channels. */ +#define S3C24A0_DMA_CHANNELS 4 + +#define MAX_S3C24A0_DMA_CHANNELS S3C24A0_DMA_CHANNELS + +#define DMA_CH0 0 +#define DMA_CH1 1 +#define DMA_CH2 2 +#define DMA_CH3 3 + +#define DMA_BUF_WR 1 +#define DMA_BUF_RD 0 + +typedef void (*dma_callback_t)(void *buf_id, int size); + +/* S3C24A0 DMA API */ +extern int elfin_request_dma(const char *device_id, dmach_t channel, + dma_callback_t write_cb, dma_callback_t read_cb); +extern int elfin_dma_queue_buffer(dmach_t channel, void *buf_id, + dma_addr_t data, int size, int write); +extern int elfin_dma_flush_all(dmach_t channel); +extern void elfin_free_dma(dmach_t channel); +extern int elfin_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr); +extern int elfin_dma_stop(dmach_t channel); + +#endif /* __ASM_ARCH_DMA_H__ */ diff --git a/include/asm-arm/arch-s3c24a0/entry-macro.S b/include/asm-arm/arch-s3c24a0/entry-macro.S new file mode 100644 index 00000000..e91043e6 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/entry-macro.S @@ -0,0 +1,32 @@ +/* + * arch/armnommu/mach-s3c24a0/entry-macro.S + * + * Heechul Yun + * Hyok S. Choi for fixup patch + */ + + +#include + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov \irqstat, #io_p2v(0x40000000) @ Virtual Address + add \irqstat, \irqstat,#0x00200000 @ INT Ctrl base + + ldr \irqnr, [\irqstat,#0x14] @ INTOFFSET + cmp \irqnr,#0 + beq 1001f + mov r0, \irqnr + bl fixup_irq + b 1002f +1001: + ldr \irqstat,[\irqstat,#-0x4] @ INTPND + tst \irqstat,#0x1 @ EINT0_2 happens ? +1002: + + .endm + .macro disable_fiq + .endm + + /* we don't have an irq priority table */ + .macro irq_prio_table + .endm + diff --git a/include/asm-arm/arch-s3c24a0/hardware.h b/include/asm-arm/arch-s3c24a0/hardware.h new file mode 100644 index 00000000..6f07c189 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/hardware.h @@ -0,0 +1,143 @@ +/* + * include/asm-arm/arch-s3c24a0/hardware.h + * + * $Id: hardware.h,v 1.3 2006/12/12 13:13:07 gerg Exp $ + * + * 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 + */ + +/* + * based on S3C2410.h modified by hcyun + * modified for hybrid MM support (uClinux and Linux) by Hyok S. Choi + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#ifndef CONFIG_MMU +/* called on reserve_node_zero() for reserving mmu section table */ +#ifndef CONFIG_DRAM_BASE + #define CONFIG_DRAM_BASE 0x10000000 +#endif + +#define MACH_RESERVE_BOOTMEM() do { \ + reserve_bootmem_node(pgdat, (CONFIG_DRAM_BASE + 0x4000), 0x4000); \ + } while(0) + +#define MACH_FREE_BOOTMEM() + +#endif /* !CONFIG_MMU */ + +#define PCIO_BASE 0 + +#if defined(CONFIG_DRAM_BASE) && defined(CONFIG_DRAM_SIZE) + #define PA_SDRAM_BASE (CONFIG_DRAM_BASE) + #define MEM_SIZE (CONFIG_DRAM_SIZE) +#else + #define PA_SDRAM_BASE 0x10000000 + #define MEM_SIZE 0x04000000 +#endif + +/* + * S3C24A0 internal I/O mappings + * + * We have the following mapping: + * phys virt + * 40000000 e0000000 + */ + +#ifdef CONFIG_MMU + +#define VIO_BASE 0xe0000000 /* virtual start of IO space */ +#define PIO_START 0x40000000 /* physical start of IO space */ + +#define io_p2v(x) ((x) | 0xa0000000) +#define io_v2p(x) ((x) & ~0xa0000000) + +#define io_p2v_isp(x) ((x) + 0xec000000) +#define io_v2p_isp(x) ((x) - 0xec000000) + + +#else /* UCLINUX */ + +#define PIO_START 0x40000000 +#define VIO_BASE PIO_START + +#define io_p2v(x) (x) +#define io_v2p(x) (x) + +#define io_p2v_isp(x) (x) +#define io_v2p_isp(x) (x) + + +#endif /* CONFIG_MMU */ + + +#ifndef __ASSEMBLY__ +#include + +/* + * This __REG() version gives the same results as the one above, except + * that we are fooling gcc some how so it generates far better and smaller + * assembly code for access to contigous registers. It's a shame that gcc + * doesn't guess this by itself + */ +typedef struct { volatile u32 offset[4096]; } __regbase; +#define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] +#define __REG(x) __REGP(io_p2v(x)) + +/* Let's kick gcc's ass again... */ +# define __REG2(x,y) \ + ( __builtin_constant_p(y) ? (__REG((x) + (y))) \ + : (*(volatile u32 *)((u32)&__REG(x) + (y))) ) + +#define __PREG(x) (io_v2p((u32)&(x))) + +/*SEO add to allocate vertual memory address for ISP1583 */ +#define __REG_ISP(x) io_p2v_isp(x) +#define __PREG_ISP(x) io_v2p_isp(x) + + +#else /* __ASSEMBLY__ */ + +# define __REG(x) io_p2v(x) +# define __PREG(x) io_v2p(x) + +#endif /* __ASSEMBLY__ */ + +#include "S3C24A0.h" + +#ifndef __ASSEMBLY__ + +#define EINT_PULLUP_EN (0) +#define EINT_PULLUP_DIS (1) + +#define EINT_LOW_LEVEL (0x0) +#define EINT_HIGH_LEVEL (0x1) +#define EINT_FALLING_EDGE (0x2) +#define EINT_RISING_EDGE (0x4) +#define EINT_BOTH_EDGES (0x6) + +extern int set_external_irq(int irq, int edge, int pullup); + +#endif + +#ifdef CONFIG_ARCH_SMDK24A0 +#include "smdk.h" +#else +#error not defined board +#endif + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-s3c24a0/ide.h b/include/asm-arm/arch-s3c24a0/ide.h new file mode 100644 index 00000000..0de43cca --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/ide.h @@ -0,0 +1,147 @@ +/* + * include/asm-arm/arch-s3c24a0/ide.h + * + * + * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h + * + * Changes + * + * 2004/06/10 SPJ CPLD IDE support + * 2004/06/13 CPLD IDE and USB csupport for SPJ + * + */ + +#include +#include +#include + + +#ifndef MAX_HWIFS + #define MAX_HWIFS 1 +#else + #undef MAX_HWIFS + #define MAX_HWIFS 1 +#endif + +#define CPLD_IDE_DEBUG // hcyun + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + ide_ioreg_t reg; + + memset(hw, 0, sizeof(*hw)); + + reg = (ide_ioreg_t)data_port; + + /* increasing 8 */ + hw->io_ports[IDE_DATA_OFFSET] = reg + 0; + hw->io_ports[IDE_ERROR_OFFSET] = reg + (1 << 3); + hw->io_ports[IDE_NSECTOR_OFFSET] = reg + (2 << 3); + hw->io_ports[IDE_SECTOR_OFFSET] = reg + (3 << 3); + hw->io_ports[IDE_LCYL_OFFSET] = reg + (4 << 3); + hw->io_ports[IDE_HCYL_OFFSET] = reg + (5 << 3); + hw->io_ports[IDE_SELECT_OFFSET] = reg + (6 << 3); + hw->io_ports[IDE_STATUS_OFFSET] = reg + (7 << 3); + + hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; + + if (irq) + *irq = 0; +} + + +/* + * CPLD IDE reset. to reset first assert 0 and then assert 1 + */ + +static __inline__ void ide_set_reset(int on) +{ + volatile unsigned char *usb_reset = (unsigned char *)(SMDK_CPLD_USB_VIO+0x00800000); + volatile unsigned char *ide_reset = (unsigned char *)(SMDK_CPLD_IDE_VIO+0x00800000); + + if ( on ) { + /* turn CPLD to IDE mode */ + *ide_reset = 0x02; + + /* turn on IDE */ + *ide_reset = 0x03; + + } else { + /* turn off IDE */ + *ide_reset = 0x02; + + *ide_reset = 0x02; + } + +/* + *ide_reset = 0x1; + *usb_reset = 0x0; + *usb_reset = 0x1; +*/ + +} + + +/* + * Register the standard ports for this architecture with the IDE driver. + */ +static __inline__ void +ide_init_default_hwifs(void) +{ + /* + A7 A6 A5 A4 A3 <-- CPLD address line used + + CE2 CE1 A2 A1 A0 IORD IOWR + --------------------------------- + 1 0 0 0 0 data port + .. + .. + + 0 1 1 1 0 control port + + data port = SMDK_CPLD_IDE_VIO + 0x80 + control port = SMDK_CPLD_IDE_VIO + 0x70 + + */ + + /* Nothing to declare... */ + + int ret; + + hw_regs_t hw; + + ide_init_hwif_ports(&hw, SMDK_CPLD_IDE_VIO + 0x80, SMDK_CPLD_IDE_VIO + 0x70, NULL); + + hw.irq = SMDK_CPLD_IDE_IRQ; + + ide_register_hw(&hw, NULL); + + +#ifdef CPLD_IDE_DEBUG + printk("SMDK24A0 : IDE initialize - hcyun \n"); + printk("!!FIXME!! IDE and cs8900 are controlled by SROM bank1 and need different timing and bus width\n"); +#endif + + bank1_set_state(B1_IDE_PIO4); + + // ide reset + ide_set_reset(0); + + mdelay(250); + + ide_set_reset(1); + + mdelay(500); // wait 250ms see ATA spec + + printk("riging edge interrupt\n"); + ret = set_external_irq(SMDK_CPLD_IDE_IRQ, EINT_RISING_EDGE, EINT_PULLUP_EN); + + if (ret) + printk("ERROR: irq set failed\n"); + +} diff --git a/include/asm-arm/arch-s3c24a0/io.h b/include/asm-arm/arch-s3c24a0/io.h new file mode 100644 index 00000000..ce37e855 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/io.h @@ -0,0 +1,45 @@ +/* + * include/asm-arm/arch-s3c24a0/io.h + * + * $Id: io.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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 + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#if 0 +/* + * Generic virtual read/write + */ +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#endif + +#define iomem_valid_addr(iomem,sz) (1) +#define iomem_to_phys(iomem) (iomem) + +#endif /* __ASM_ARM_ARCH_IO_H */ diff --git a/include/asm-arm/arch-s3c24a0/irq.h b/include/asm-arm/arch-s3c24a0/irq.h new file mode 100644 index 00000000..fdd04c3d --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/irq.h @@ -0,0 +1,16 @@ +/* + * include/asm-arm/arch-s3c24a0/irq.h + * + * $Id: irq.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + */ + +/* + * This prototype is required for cascading of multiplexed interrupts. + * Since it doesn't exist elsewhere, we'll put it here for now. + */ +extern unsigned int fixup_irq(int i); +extern void do_IRQ(int irq, struct pt_regs *regs); diff --git a/include/asm-arm/arch-s3c24a0/irqs.h b/include/asm-arm/arch-s3c24a0/irqs.h new file mode 100644 index 00000000..ca6a3ea6 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/irqs.h @@ -0,0 +1,144 @@ +/* + * include/asm-arm/arch-s3c24a0/irqs.h + * + * $Id: irqs.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + */ + +/* +-+ + * |m| +---------+ + * sub-irq ------\ |a|--> | sub-irq | + * sources ------/ |s| | status |\ + * |k| +---------+ \ + * +-+ \ + * \ + * +-+ \ +-+ + * |m| +---------+ +---> |m| +--------+ + * external irq ----\ |a|--> | ext-irq |---------> |a|--\ |main-irq| + * sources ----/ |s| | status | +-> |s|--/ | status | + * |k| +---------+ / |k| +--------+ + * +-+ / +-+ + * / + * / + * / + * irq sources -------------------------/ + * + */ + + +/* + * We have three groups. + * #0 : Normal (or Main) IRQs + * #1 : Sub-IRQs + * #2 : External IRQs + */ +#define NR_IRQ_GRP (32) /* number of irqs in group */ +#define IRQ_GRP0_START (0) +#define IRQ_GRP1_START (IRQ_GRP0_START + NR_IRQ_GRP) +#define IRQ_GRP2_START (IRQ_GRP1_START + NR_IRQ_GRP) + +#define NR_IRQS (NR_IRQ_GRP * 3) + +#define SUBIRQ_ENC(x) ((x) + IRQ_GRP1_START) +#define SUBIRQ_DEC(x) ((x) - IRQ_GRP1_START) +#define EINTIRQ_ENC(x) ((x) + IRQ_GRP2_START) +#define EINTIRQ_DEC(x) ((x) - IRQ_GRP2_START) + +/* Interrupt controller */ +#define IRQ_EINT0_2 (0) /* External interrupt 0 ~ 2 */ +#define IRQ_EINT3_6 (1) /* External interrupt 3 ~ 6 */ +#define IRQ_EINT7_10 (2) /* External interrupt 7 ~ 10 */ +#define IRQ_EINT11_14 (3) /* External interrupt 11 ~ 14 */ +#define IRQ_EINT15_18 (4) /* External interrupt 15 ~ 18 */ +#define IRQ_TIC (5) /* RTC time tick */ +#define IRQ_DCTQ (6) /* DCTQ */ +#define IRQ_MC (7) /* MC */ +#define IRQ_ME (8) /* ME */ +#define IRQ_KEYPAD (9) /* Keypad */ +#define IRQ_TIMER0 (10) /* Timer 0 */ +#define IRQ_TIMER1 (11) /* Timer 1 */ +#define IRQ_TIMER2 (12) /* Timer 2 */ +#define IRQ_TIMER3_4 (13) /* Timer 3, 4 */ +#define IRQ_LCD_POST (14) /* LCD/POST */ +#define IRQ_CAM_C (15) /* Camera Codec */ +#define IRQ_WDT_BATFLT (16) /* WDT/BATFLT */ +#define IRQ_UART0 (17) /* UART 0 */ +#define IRQ_CAM_P (18) /* Camera Preview */ +#define IRQ_MODEM (19) /* Modem */ +#define IRQ_DMA (20) /* DMA channels for S-bus */ +#define IRQ_SDI (21) /* SDI MMC */ +#define IRQ_SPI0 (22) /* SPI 0 */ +#define IRQ_UART1 (23) /* UART 1 */ +#define IRQ_AC97_NFLASH (24) /* AC97/NFALASH */ +#define IRQ_USBD (25) /* USB device */ +#define IRQ_USBH (26) /* USB host */ +#define IRQ_IIC (27) /* IIC */ +#define IRQ_IRDA_MSTICK (28) /* IrDA/MSTICK */ +#define IRQ_VLX_SPI1 (29) /* SPI 1 */ +#define IRQ_RTC (30) /* RTC alaram */ +#define IRQ_ADC_PENUPDN (31) /* ADC EOC/Pen up/Pen down */ + +/* SUB IRQ */ +#define IRQ_RXD0 SUBIRQ_ENC(0) +#define IRQ_TXD0 SUBIRQ_ENC(1) +#define IRQ_ERR0 SUBIRQ_ENC(2) +#define IRQ_RXD1 SUBIRQ_ENC(3) +#define IRQ_TXD1 SUBIRQ_ENC(4) +#define IRQ_ERR1 SUBIRQ_ENC(5) +#define IRQ_IRDA SUBIRQ_ENC(6) +#define IRQ_MSTICK SUBIRQ_ENC(7) +#define IRQ_TIMER3 SUBIRQ_ENC(11) +#define IRQ_TIMER4 SUBIRQ_ENC(12) +#define IRQ_WDT SUBIRQ_ENC(13) +#define IRQ_BATFLT SUBIRQ_ENC(14) +#define IRQ_POST SUBIRQ_ENC(15) +#define IRQ_DISP_FIFO SUBIRQ_ENC(16) +#define IRQ_PENUP SUBIRQ_ENC(17) +#define IRQ_PENDN SUBIRQ_ENC(18) +#define IRQ_ADC SUBIRQ_ENC(19) +#define IRQ_DISP_FRAME SUBIRQ_ENC(20) +#define IRQ_NFLASH SUBIRQ_ENC(21) +#define IRQ_AC97 SUBIRQ_ENC(22) +#define IRQ_SPI1 SUBIRQ_ENC(23) +#define IRQ_VLX SUBIRQ_ENC(24) +#define IRQ_DMA0 SUBIRQ_ENC(25) +#define IRQ_DMA1 SUBIRQ_ENC(26) +#define IRQ_DMA2 SUBIRQ_ENC(27) +#define IRQ_DMA3 SUBIRQ_ENC(28) + +/* External IRQ */ +#define IRQ_EINT0 EINTIRQ_ENC(0) +#define IRQ_EINT1 EINTIRQ_ENC(1) +#define IRQ_EINT2 EINTIRQ_ENC(2) +#define IRQ_EINT3 EINTIRQ_ENC(3) +#define IRQ_EINT4 EINTIRQ_ENC(4) +#define IRQ_EINT5 EINTIRQ_ENC(5) +#define IRQ_EINT6 EINTIRQ_ENC(6) +#define IRQ_EINT7 EINTIRQ_ENC(7) +#define IRQ_EINT8 EINTIRQ_ENC(8) +#define IRQ_EINT9 EINTIRQ_ENC(9) +#define IRQ_EINT10 EINTIRQ_ENC(10) +#define IRQ_EINT11 EINTIRQ_ENC(11) +#define IRQ_EINT12 EINTIRQ_ENC(12) +#define IRQ_EINT13 EINTIRQ_ENC(13) +#define IRQ_EINT14 EINTIRQ_ENC(14) +#define IRQ_EINT15 EINTIRQ_ENC(15) +#define IRQ_EINT16 EINTIRQ_ENC(16) +#define IRQ_EINT17 EINTIRQ_ENC(17) +#define IRQ_EINT18 EINTIRQ_ENC(18) +#define IRQ_EINT19 EINTIRQ_ENC(19) +#define IRQ_EINT20 EINTIRQ_ENC(20) +#define IRQ_EINT21 EINTIRQ_ENC(21) +#define IRQ_EINT22 EINTIRQ_ENC(22) +#define IRQ_EINT23 EINTIRQ_ENC(23) +#define IRQ_EINT24 EINTIRQ_ENC(24) +#define IRQ_EINT25 EINTIRQ_ENC(25) +#define IRQ_EINT26 EINTIRQ_ENC(26) +#define IRQ_EINT27 EINTIRQ_ENC(27) +#define IRQ_EINT28 EINTIRQ_ENC(28) +#define IRQ_EINT29 EINTIRQ_ENC(29) +#define IRQ_EINT30 EINTIRQ_ENC(30) +#define IRQ_EINT31 EINTIRQ_ENC(31) diff --git a/include/asm-arm/arch-s3c24a0/keyboard.h b/include/asm-arm/arch-s3c24a0/keyboard.h new file mode 100644 index 00000000..e49c001c --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/keyboard.h @@ -0,0 +1,134 @@ +/* + * keyboard.h + * + * $Id: keyboard.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + */ + +#ifndef _S3C24A0_KEYBOARD_H +#define _S3C24A0_KEYBOARD_H + +#define kbd_disable_irq() do { } while(0); +#define kbd_enable_irq() do { } while(0); + +#define k_leds(x...) +#define k_setkeycode(x...) +#define k_getkeycode(x...) +#define k_unexpected_up(x...) (1) + +/* S3C24A0 SPI */ + +#if 1 // hcyun +extern int elfin_kbd_init (void); +#define kbd_init_hw() elfin_kbd_init() +#else +#define kbd_init_hw() do {} while(0); +#endif + +/* Generic Keyboard Scan Codes */ +#define KK_NONE 0x00 +#define KK_ESC 0x01 +#define KK_F1 0x3b +#define KK_F2 0x3c +#define KK_F3 0x3d +#define KK_F4 0x3e +#define KK_F5 0x3f +#define KK_F6 0x40 +#define KK_F7 0x41 +#define KK_F8 0x42 +#define KK_F9 0x43 +#define KK_F10 0x44 +#define KK_F11 0x57 +#define KK_F12 0x58 +#define KK_PRNT 0x63 /* PrintScreen */ +#define KK_SCRL 0x46 /* Scroll Lock */ +#define KK_BRK 0x77 /* Break */ +#define KK_AGR 0x29 /* ` */ +#define KK_1 0x02 +#define KK_2 0x03 +#define KK_3 0x04 +#define KK_4 0x05 +#define KK_5 0x06 +#define KK_6 0x07 +#define KK_7 0x08 +#define KK_8 0x09 +#define KK_9 0x0a +#define KK_0 0x0b +#define KK_MINS 0x0c /* - */ +#define KK_EQLS 0x0d /* = */ +#define KK_BKSP 0x0e /* BKSP */ +#define KK_INS 0x6e /* Insert */ +#define KK_HOME 0x66 +#define KK_PGUP 0x68 +#define KK_NUML 0x45 +#define KP_SLH 0x62 /* KP / */ +#define KP_STR 0x37 /* KP * */ +#define KP_MNS 0x4a /* KP - */ +#define KK_TAB 0x0f +#define KK_Q 0x10 +#define KK_W 0x11 +#define KK_E 0x12 +#define KK_R 0x13 +#define KK_T 0x14 +#define KK_Y 0x15 +#define KK_U 0x16 +#define KK_I 0x17 +#define KK_O 0x18 +#define KK_P 0x19 +#define KK_LSBK 0x1a /* [ */ +#define KK_RSBK 0x1b /* ] */ +#define KK_ENTR 0x1c +#define KK_DEL 0x6f +#define KK_END 0x6b +#define KK_PGDN 0x6d +#define KP_7 0x47 +#define KP_8 0x48 +#define KP_9 0x49 +#define KP_PLS 0x37 /* KP + */ +#define KK_CAPS 0x3a +#define KK_A 0x1e +#define KK_S 0x1f +#define KK_D 0x20 +#define KK_F 0x21 +#define KK_G 0x22 +#define KK_H 0x23 +#define KK_J 0x24 +#define KK_K 0x25 +#define KK_L 0x26 +#define KK_SEMI 0x27 /* ; */ +#define KK_SQOT 0x28 /* ' */ +#define KK_HASH 0x29 /* ` */ +#define KP_4 0x4b +#define KP_5 0x4c +#define KP_6 0x4d +#define KK_LSFT 0x2a /* L SHIFT */ +#define KK_BSLH 0x2b /* \ */ +#define KK_Z 0x2c +#define KK_X 0x2d +#define KK_C 0x2e +#define KK_V 0x2f +#define KK_B 0x30 +#define KK_N 0x31 +#define KK_M 0x32 +#define KK_COMA 0x33 /* , */ +#define KK_DOT 0x34 /* . */ +#define KK_FSLH 0x35 /* / */ +#define KK_RSFT 0x36 /* R SHIFT */ +#define KK_UP 0x67 +#define KP_1 0x4f +#define KP_2 0x50 +#define KP_3 0x51 +#define KP_ENT 0x60 /* KP Enter */ +#define KK_LCTL 0x1d /* L CTRL */ +#define KK_LALT 0x38 /* L ALT */ +#define KK_SPCE 0x39 /* SPACE */ +#define KK_RALT 0x64 /* R ALT */ +#define KK_RCTL 0x61 /* R CTRL */ +#define KK_LEFT 0x69 +#define KK_DOWN 0x6c +#define KK_RGHT 0x6a +#define KP_0 0x52 +#define KP_DOT 0x53 /* KP . */ +#define KK_21 0x21 + +#endif /* _S3C24A0_KEYBOARD_H */ diff --git a/include/asm-arm/arch-s3c24a0/memory.h b/include/asm-arm/arch-s3c24a0/memory.h new file mode 100644 index 00000000..5e7f1c89 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/memory.h @@ -0,0 +1,44 @@ +/* + * include/asm-arm/arch-s3c24a0/memory.h + * + * $Id: memory.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * Copyright (C) Heechul Yun + * Copyright (C) Hyok S. Choi + * + * 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. + */ + +#ifndef __ASM_ARCH_MEMORY_H_ +#define __ASM_ARCH_MEMORY_H_ + +#ifndef CONFIG_MMU + +#ifndef TASK_SIZE_26 +#define TASK_SIZE END_MEM +#define TASK_SIZE_26 TASK_SIZE +#endif + +#define PAGE_OFFSET (PHYS_OFFSET) + + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((unsigned long) (ppage)) + +#endif /* !CONFIG_MMU */ + +#ifndef CONFIG_DRAM_BASE +#define PHYS_OFFSET (0x10000000UL) +#define END_MEM (0x13000000UL) +#else +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) +#endif + +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + + +#endif /* __ASM_ARCH_MEMORY_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/param.h b/include/asm-arm/arch-s3c24a0/param.h new file mode 100644 index 00000000..f9ddfe12 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/param.h @@ -0,0 +1,11 @@ +/* + * include/asm-arm/arch-s3c24a0/param.h + * + * $Id: param.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + */ + +/* FIXME: Nothing to do */ diff --git a/include/asm-arm/arch-s3c24a0/s3c24a0-common.h b/include/asm-arm/arch-s3c24a0/s3c24a0-common.h new file mode 100644 index 00000000..77443911 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/s3c24a0-common.h @@ -0,0 +1,35 @@ +/* + * include/asm-arm/arch-s3c24a0/s3c24a0-common.h + * + * $Id: s3c24a0-common.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + */ +#ifndef _INCLUDE_LINUETTE_COMMON_H_ +#define _INCLUDE_LINUETTE_COMMON_H_ +#ifndef __ASSEMBLY__ + +/* + * New Audio Format MSM9842 + * + * NOTE: + * refer to linux/soundcard.h + */ +#define AFMT_4_ADPCM2 0x80000000 // 4bit ADPCM2 +#define AFMT_5_ADPCM2 0x40000000 // 5bit ADPCM2 +#define AFMT_6_ADPCM2 0x20000000 // 6bit ADPCM2 +#define AFMT_7_ADPCM2 0x10000000 // 7bit ADPCM2 +#define AFMT_8_ADPCM2 0x08000000 // 8bit ADPCM2 + +/* + * device name + */ +#define BIOS_NAME "apm_bios" + +/* definition of key/buttons */ +#include "s3c24a0-key.h" + +#endif /* __ASSEMBLY__ */ +#endif /* _INCLUDE_LINUETTE_COMMON_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h b/include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h new file mode 100644 index 00000000..39fed187 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h @@ -0,0 +1,156 @@ +/* + * include/asm-arm/arch-s3c24a0/s3c24a0-ioctl.h + * + * ioctl's defintion. + * + * $Id: s3c24a0-ioctl.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + */ +#include +#include "s3c24a0-common.h" + +#ifndef _INCLUDE_LINUETTE_IOCTL_H_ +#define _INCLUDE_LINUETTE_IOCTL_H_ +#ifndef __ASSEMBLY__ + +/* + * see Documentation/ioctl-number.txt + */ +#define IOC_MAGIC ('h') + +/* + * for touch devices + */ +typedef struct { + unsigned short pressure; + unsigned short x; + unsigned short y; + unsigned short pad; +} TS_RET; + +typedef struct { + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +} TS_CAL; + +#define TS_GET_CAL _IOR(IOC_MAGIC, 0x81, TS_CAL) +#define TS_SET_CAL _IOW(IOC_MAGIC, 0x82, TS_CAL) +#define TS_ENABLE _IO (IOC_MAGIC, 0x90) +#define TS_DISABLE _IO (IOC_MAGIC, 0x91) + +/* + * below ioctl function is for hacker and iom + */ +/* + * brightness control + */ +#define GET_BRIGHTNESS _IOR(IOC_MAGIC, 0x83, unsigned int) +#define SET_BRIGHTNESS _IOW(IOC_MAGIC, 0x84, unsigned int) +#define GET_BRIGHTNESS_INFO _IOR(IOC_MAGIC, 0x8e, unsigned int) + +/* + . BATTERY_RET.level + 0~ : valid (usually, values from ADC or 0 ~ 100%) + -1 : Unknown + _ Remaining battery life + + . BATTERY_RET.ac + 0x00 : Off-line + 0x01 : On-line + 0xff : Unknown + _ AC line status + + . BATTERY_RET.battery + 0x01 : Full (== 100%) + 0x02 : Critical (sleep definitely) + 0x03 : Charging + 0x04 : Low (warning) + 0x10 : backup battery is low, change it + 0x40 : backup battery is present + 0x80 : system battery is present + 0xff : Unknown + _ Battery status +*/ + +#define AC_OFF_LINE 0x00 +#define AC_ON_LINE 0x01 +#define AC_UNKNOWN 0xff + +#define BATTERY_FULL 0x01 +#define BATTERY_CRIT 0x02 +#define BATTERY_CHARGE 0x03 +#define BATTERY_LOW 0x04 +#define battery_stat(x) ((x) & 0xf) +#define BATTERY_BAK_LOW 0x10 +#define BATTERY_BAK 0x40 +#define BATTERY_SYS 0x80 +#define BATTERY_UNKNOWN 0xff + +#define BATTERY_TIMER_STOP 0 /* unit: sec. */ + +typedef struct { + int level, voltage, raw; + unsigned char ac; + unsigned char battery; +} BATTERY_RET; +#define GET_BATTERY_STATUS _IOR(IOC_MAGIC, 0x85, BATTERY_RET) +#define SET_BATTERY_TIMER _IOR(IOC_MAGIC, 0x8f, unsigned int) + +/* + * for apm_bios + */ +#define PM_STATE_QUERY 0x20 +#define PM_STATE_D0 0 +#define PM_STATE_D1 1 +#define PM_STATE_D2 2 +#define PM_STATE_D3 3 +#define PM_STATE_UNKNOWN (-1) + +struct pm_usr_dev { + unsigned long dev; + unsigned long type, id; + int state; +}; +#define PM_DEV _IOW(IOC_MAGIC, 0x86, struct pm_usr_dev) + +/* if some devices gives veto, do not sleep */ +#define USR_SUSPEND _IO (IOC_MAGIC, 0x87) +/* sleep simply */ +#define SYS_SUSPEND _IO (IOC_MAGIC, 0x88) +/* LCD/INPUT/removable sleep + or if not, sleep as soon as possible */ +#define STANDBY _IO (IOC_MAGIC, 0x89) +/* wakeup devices */ +#define RESUME _IO (IOC_MAGIC, 0x8a) + +/* + * for /dev/misc/apm_bios + */ +#define LED_ON 0x01 +#define LED_OFF 0x00 +#define LED_BLINK 0x04 +#define LED_BLINK_RATE 0x08 /* variable-rate blink */ +#define LED_READ_ONLY 0x80 +#define LED_COLOR 0x40 + +typedef struct { + unsigned int index; /* LED index to control */ + unsigned int stat; /* control command or current status */ + unsigned int rate; /* blinking rate */ + unsigned int color; /* LED color */ + unsigned int info; /* capable function */ +} LED_RET; + +#define GET_LED_NO _IOR(IOC_MAGIC, 0x8b, unsigned int) +#define GET_LED_STATUS _IOR(IOC_MAGIC, 0x8c, LED_RET) +#define SET_LED_STATUS _IOW(IOC_MAGIC, 0x8d, LED_RET) + +#include "s3c24a0-machine.h" +#endif /* __ASSEMBLY__ */ +#endif /* _INCLUDE_LINUETTE_IOCTL_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/s3c24a0-key.h b/include/asm-arm/arch-s3c24a0/s3c24a0-key.h new file mode 100644 index 00000000..ec6876a6 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/s3c24a0-key.h @@ -0,0 +1,116 @@ +/* + * include/asm-arm/arch-s3c24a0/s3c24a0-key.h + * + * $Id: s3c24a0-key.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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. + * + * Changes + * + * 2004/06/15 Added SPJ key scancode + */ + +#ifndef _SPJ_KEY_H_ +#define _SPJ_KEY_H_ +#ifndef __ASSEMBLY__ + +#define KEY_RELEASED 0 +#define KEY_PRESSED 1 + +/* + * Definition of Generic Key Scancode + */ +#define SCANCODE_LEFT 0x69 +#define SCANCODE_RIGHT 0x6a +#define SCANCODE_UP 0x67 +#define SCANCODE_DOWN 0x6c +#define SCANCODE_ENTER 0x1c +#define SCANCODE_PAGE_UP 0x68 /* Page Up */ +#define SCANCODE_PAGE_DOWN 0x6d /* Page Down */ +#define SCANCODE_BKSP 0x0e /* Back Space */ + +/* + * Key PAD + */ +#define SCANCODE_PAD_0 0x52 +#define SCANCODE_PAD_1 0x4f +#define SCANCODE_PAD_2 0x50 +#define SCANCODE_PAD_3 0x51 +#define SCANCODE_PAD_4 0x4b +#define SCANCODE_PAD_5 0x4c +#define SCANCODE_PAD_6 0x4d +#define SCANCODE_PAD_7 0x47 +#define SCANCODE_PAD_8 0x48 +#define SCANCODE_PAD_9 0x49 +#define SCANCODE_PAD_MINUS 0x4a +#define SCANCODE_PAD_PLUS 0x4e +#define SCANCODE_PAD_ENTER 0x60 +#define SCANCODE_PAD_PERIOD 0x53 +#define SCANCODE_PAD_SLASH 0x62 +#define SCANCODE_PAD_ASTERISK 0x37 + +/* + * Function Key + */ +#define SCANCODE_F5 0x3f +#define SCANCODE_F6 0x40 +#define SCANCODE_F7 0x41 +#define SCANCODE_F8 0x42 +#define SCANCODE_F9 0x43 +#define SCANCODE_F10 0x44 +#define SCANCODE_F11 0x57 +#define SCANCODE_F12 0x58 + +/* + * Undefined Region + */ +#define SCANCODE_U1 0x78 /* Unknown */ +#define SCANCODE_U2 0x79 /* Unknown */ +#define SCANCODE_U3 0x70 /* Unknown */ +#define SCANCODE_U4 0x71 /* Unknown */ +#define SCANCODE_U5 0x72 /* Unknown */ +#define SCANCODE_U6 0x73 /* Unknown */ +#define SCANCODE_U7 0x74 /* Unknown */ +#define SCANCODE_U8 0x75 /* Unknown */ +#define SCANCODE_U9 0x76 /* Unknown */ + +/* + * Common key definition for PDA + */ +#define SCANCODE_POWER 0x7a +#define SCANCODE_RECORD 0x7b +#define SCANCODE_ACTION SCANCODE_ENTER +#define SCANCODE_SLIDE_UP SCANCODE_PAGE_UP +#define SCANCODE_SLIDE_DOWN SCANCODE_PAGE_DOWN +#define SCANCODE_SLIDE_CENTER SCANCODE_PAD_ENTER + +/* + * Common key definition for Phone + */ +#define SCANCODE_ASTERISK SCANCODE_PAD_ASTERISK +#define SCANCODE_SHARP SCANCODE_PAD_MINUS +#define SCANCODE_SEND 0x7c +#define SCANCODE_END 0x7d +#define SCANCODE_MENU 0x7e +#define NCODE_CLR 0x7f + + +/* These are the scancodes for SPJ buttons on the SMDK24a0 */ + +#define scPOWER 120 /* sw1 - 0x78 */ +#define scMENU 121 /* sw3 - 0x79 */ +#define scTOOL 122 /* sw13 - 0x7a */ +#define scRETURN 123 /* sw11 - 0x7b */ +#define scVOLUP 124 /* sw5 - 0x7c */ +#define scVOLDOWN 125 /* sw10 - 0x7d */ +#define scHOLD 126 /* sw21 - 0x7e*/ +#define scUP 103 /* sw2, - 0x67 keycode up*/ +#define scRIGHT 106 /* sw8, - 0x6a keycode right */ +#define scLEFT 105 /* sw6, - 0x69 keycode left */ +#define scDOWN 108 /* sw12, - 0x6c keycode down */ +#define scACTION 96 /* sw7, - 0x60 keycode keypad enter */ + +#endif /* __ASSEMBLY__ */ +#endif /* _SPJ_KEY_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/s3c24a0-machine.h b/include/asm-arm/arch-s3c24a0/s3c24a0-machine.h new file mode 100644 index 00000000..5a80361f --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/s3c24a0-machine.h @@ -0,0 +1,223 @@ +/* + * include/asm-arm/arch-s3c24a0/s3c24a0-machine.h + * + * $Id: s3c24a0-machine.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * vendor/machine specifice ioctl function + * + * extended ioctl for MTD + * change the permission of MTDPART + */ + +/* + *for CONFIG_SA1100_WISMO + */ +#define WS_SET_MODEM_MODE _IOW(IOC_MAGIC, 0xc0, unsigned long) +#define WS_GET_MODEM_MODE _IOR(IOC_MAGIC, 0xc1, unsigned long) +#define WS_MODEM_MODE_OFF 0x01 +#define WS_MODEM_MODE_READY 0x02 /* i,e,. PowerDown Mode */ +#define WS_MODEM_MODE_CALL 0x03 /* i,e,. Normal Mode */ + +#define WS_KEYPAD_LED 0 +#define WS_7COLOR_LED 1 + +#define WS_SUBLCD_ON _IO (IOC_MAGIC, 0xc2) +#define WS_SUBLCD_OFF _IO (IOC_MAGIC, 0xc3) +#define WS_SUBLCD_DRAW _IO (IOC_MAGIC, 0xc4) +#define WS_SUBLCD_BLITE_ON _IO (IOC_MAGIC, 0xc5) +#define WS_SUBLCD_BLITE_OFF _IO (IOC_MAGIC, 0xc6) + + +typedef struct { + unsigned char reserved; + unsigned char sec; /* seconds 0 ~ 59 */ + unsigned char min; /* min 0 - 59 */ + unsigned char hour; /* Hour 0 ~ 59 */ + unsigned char day; /* Day 0 ~ 23 */ + unsigned char month; /* Month 1 ~ 12 */ +} WS_DATE_T; +#define WS_SET_DATE _IOW(IOC_MAGIC, 0xc7, WS_DATE_T) + +typedef struct { + unsigned char reserved; + unsigned char batt; + unsigned char rssi; + unsigned char msg; + unsigned char alarm; + unsigned char alert; + unsigned char unused[2]; +} WS_ICON_T; +#define WS_SET_ICON _IOW(IOC_MAGIC, 0xc8, WS_ICON_T) + +typedef struct { + unsigned char hlt; + unsigned char llt; +} WS_MOTOR_T; +#define WS_MOTOR_ON _IOW(IOC_MAGIC, 0xc9, WS_MOTOR_T) +#define WS_MOTOR_OFF _IO (IOC_MAGIC, 0xca) +#define WS_TOUCH_ON _IO (IOC_MAGIC, 0xcb) +#define WS_TOUCH_OFF _IO (IOC_MAGIC, 0xcc) +#define WS_SUBLCD_TIMER _IO (IOC_MAGIC, 0xce) + +#define WS_LCD_POWER_ON _IO (IOC_MAGIC, 0xd1) +#define WS_LCD_POWER_OFF _IO (IOC_MAGIC, 0xd2) +#define WS_LCD_BLITE_ON _IO (IOC_MAGIC, 0xd3) +#define WS_LCD_BLITE_OFF _IO (IOC_MAGIC, 0xd4) + + + +/* button definition */ +#define WS_SIDE_UP_BUTTON SCANCODE_SLIDE_UP +#define WS_VOICE_BUTTON SCANCODE_RECORD +#define WS_SIDE_DOWN_BUTTON SCANCODE_SLIDE_DOWN + +#define WS_SK1_BUTTON SCANCODE_U1 +#define WS_SK2_BUTTON SCANCODE_U2 +#define WS_SK3_BUTTON SCANCODE_U3 + +#define WS_WAP_BUTTON SCANCODE_MENU +#define WS_CLR_BUTTON SCANCODE_CLR +#define WS_SEND_BUTTON SCANCODE_SEND +#define WS_END_BUTTON SCANCODE_END + +#define WS_1_BUTTON SCANCODE_PAD_1 +#define WS_2_BUTTON SCANCODE_PAD_2 +#define WS_3_BUTTON SCANCODE_PAD_3 +#define WS_4_BUTTON SCANCODE_PAD_4 +#define WS_5_BUTTON SCANCODE_PAD_5 +#define WS_6_BUTTON SCANCODE_PAD_6 +#define WS_7_BUTTON SCANCODE_PAD_7 +#define WS_8_BUTTON SCANCODE_PAD_8 +#define WS_9_BUTTON SCANCODE_PAD_9 +#define WS_0_BUTTON SCANCODE_PAD_0 +#define WS_ASTERISK_BUTTON SCANCODE_ASTERISK +#define WS_SHARP_BUTTON SCANCODE_SHARP + +#define WS_UP_BUTTON SCANCODE_UP +#define WS_DOWN_BUTTON SCANCODE_DOWN +#define WS_LEFT_BUTTON SCANCODE_LEFT +#define WS_RIGHT_BUTTON SCANCODE_RIGHT + +/* camera definition */ +#define WS_CAM_IOC_MAGIC 'C' + +#define WS_CAM_ZOOM_21 0 /* cam : disp = 2 : 1 <== zoom-out */ +#define WS_CAM_ZOOM_11 1 /* cam : disp = 1 : 1 <== normal */ +#define WS_CAM_ZOOM_12 2 /* cam : disp = 1 : 2 <== zoom-in */ +#define WS_CAM_SET_ZOOM _IOW(WS_CAM_IOC_MAGIC, 10, int) + +struct ws_cam_set { + int res; /* resolution, WS_CAM_SIZE_??? */ +#define WS_CAM_SIZE_320x240 0 /* capture only */ +#define WS_CAM_SIZE_240x180 1 /* capture only */ +#define WS_CAM_SIZE_240x320_OV 2 /* overlay(preview) only */ +#define WS_CAM_SIZE_240x180_OV 3 /* overlay(preview) only */ + int preview_ypos; /* Y position when _res_ is WS_CAM_SIZE_240x180_OV */ +}; +#define WS_CAM_SET_PARAM _IOW(WS_CAM_IOC_MAGIC, 11, struct ws_cam_set) + +#define WS_CAM_SET_X_MIRROR _IOW(WS_CAM_IOC_MAGIC, 12, int) +#define WS_CAM_SET_Y_MIRROR _IOW(WS_CAM_IOC_MAGIC, 13, int) +#define WS_CAM_SET_EXPOSURE _IOW(WS_CAM_IOC_MAGIC, 14, unsigned long) +#define WS_CAM_SET_WHITBLNC _IOW(WS_CAM_IOC_MAGIC, 15, unsigned long) + +/* + * for CONFIG_ARCH_I519 + */ +/* Audio Path Control */ +#define HN_AUDIO_PATH _IOW(IOC_MAGIC, 0xc0, unsigned long) +#define MIC_PDA 0x0001 +#define PDA_SPK 0x0010 +#define MIC_PHONE 0x0002 +#define PHONE_RCV 0x0020 +#define PHONE_SPK 0x2000 + +#define HFK_PDA 0x0004 +#define PDA_HFK 0x0040 +#define HFK_PHONE 0x0008 +#define PHONE_HFK 0x0080 + +#define PHONE_PDA 0x0100 +#define PDA_PHONE 0x0200 + +/* for PXA-ac97 control (debugging only) */ +struct hn_ac97 { + unsigned int reg; + unsigned int val; +}; +#define HN_AC97_REG_WRITE _IOW(IOC_MAGIC, 0xc3, struct hn_ac97) +#define HN_AC97_REG_READ _IOR(IOC_MAGIC, 0xc4, struct hn_ac97) + +#define HN_ONLY_PDA_SPK _IO ('h', 0xe3) + +/* rescan external perpheral device */ +#define HN_RESCAN_ACCESSARY _IO (IOC_MAGIC, 0xc1) + +/* rescan & get battery type */ +#define HN_RESCAN_BATTERY_TYPE _IOR(IOC_MAGIC, 0xc2, unsigned int) +#define HN_BATTERY_TYPE_STD 0x0 +#define HN_BATTERY_TYPE_EXT 0x1 +#define HN_RESCAN_BATTERY_TYPE2 _IOR(IOC_MAGIC, 0xc5, unsigned int) + +/* UART & USB port switching */ +#define HN_UART_TO_PHONE _IO (IOC_MAGIC, 0xc8) +#define HN_UART_TO_PDA _IO (IOC_MAGIC, 0xc9) +#define HN_USB_TO_PHONE _IO (IOC_MAGIC, 0xca) +#define HN_USB_TO_PDA _IO (IOC_MAGIC, 0xcb) +#define HN_USB_UART_STATE _IO (IOC_MAGIC, 0xce) + +#define HN_UART_PATH_PDA 0x0001 +#define HN_UART_PATH_PHONE 0x0002 +#define HN_USB_PATH_PDA 0x0010 +#define HN_USB_PATH_PHONE 0x0020 + +/* Vibrator Control */ +#define HN_MOTOR_ON _IO (IOC_MAGIC, 0xcc) +#define HN_MOTOR_OFF _IO (IOC_MAGIC, 0xcd) + +/* DPRAM Control for communication between PDA and Phone */ + +/* DPRAM ioctls for DPRAM tty devices */ +#define HN_DPRAM_PHONE_ON _IO (IOC_MAGIC, 0xd0) +#define HN_DPRAM_PHONE_OFF _IO (IOC_MAGIC, 0xd1) +#define HN_DPRAM_PHONE_GETSTATUS _IOR(IOC_MAGIC, 0xd2, unsigned int) +#define HN_DPRAM_PHONE_DOWNLOAD _IO (IOC_MAGIC, 0xd5) + +/* return codes for HN_DPRAM_PHONE_GETSTATUS */ +#define HN_DPRAM_PHONE_STATUS_OFF 0x00 +#define HN_DPRAM_PHONE_STATUS_ON 0x01 + +/* DPRAM ioctls for DPRAM ctl device */ +#define HN_DPRAM_PPP_ENABLE _IO (IOC_MAGIC, 0xd3) +#define HN_DPRAM_PPP_DISABLE _IO (IOC_MAGIC, 0xd4) +#define HN_DPRAM_PPP_AC_ENABLE _IO (IOC_MAGIC, 0xd6) +#define HN_DPRAM_PPP_AC_DISABLE _IO (IOC_MAGIC, 0xd7) + +/* DPRAM events through /dev/dpram/ctl */ +#define HN_DPRAM_EVENT_PPP_ACCESS 0x0001 +#define HN_DPRAM_EVENT_PHONE_DN_DONE 0x0002 + +/* button definition */ +#define HN_POWER_BUTTON SCANCODE_POWER +#define HN_CAMERA_BUTTON SCANCODE_U1 +#define HN_VOICE_BUTTON SCANCODE_RECORD + +#define HN_SIDE_UP_BUTTON SCANCODE_SLIDE_UP +#define HN_SIDE_DOWN_BUTTON SCANCODE_SLIDE_DOWN + +#define HN_HOME_BUTTON SCANCODE_MENU +#define HN_BACK_BUTTON SCANCODE_CLR +#define HN_SEND_BUTTON SCANCODE_SEND +#define HN_END_BUTTON SCANCODE_END + +#define HN_UP_BUTTON SCANCODE_UP +#define HN_DOWN_BUTTON SCANCODE_DOWN +#define HN_LEFT_BUTTON SCANCODE_LEFT +#define HN_RIGHT_BUTTON SCANCODE_RIGHT +#define HN_OK_BUTTON SCANCODE_ENTER + +#define HN_EAR_SEND_BUTTON SCANCODE_U2 + +/* PXA255 clock control */ +#define HN_CLOCK_WRITE _IOW(IOC_MAGIC, 0xe1, unsigned int) +#define HN_CLOCK_READ _IOR(IOC_MAGIC, 0xe2, unsigned int) diff --git a/include/asm-arm/arch-s3c24a0/s3c24a0_nand.h b/include/asm-arm/arch-s3c24a0/s3c24a0_nand.h new file mode 100644 index 00000000..90e79900 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/s3c24a0_nand.h @@ -0,0 +1,485 @@ +/* + * s3c24a0_nand.h + * + * s3c24a0 NAND specific definiton + * + * $Id: s3c24a0_nand.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * Copyright (C) SAMSUNG MOBILE + */ + +#ifndef _S3C24A0_NAND_H_ +#define _S3C24A0_NAND_H_ + +#define bNAND_CTL(Nb) __REG(0x40c00000 + (Nb)) + +#define NFCONF bNAND_CTL(0x00) +#define NFCONT bNAND_CTL(0x04) +#define NFCMMD bNAND_CTL(0x08) +#define NFADDR bNAND_CTL(0x0c) +#define NFDATA bNAND_CTL(0x10) +#define NFMECCDATA0 bNAND_CTL(0x14) +#define NFMECCDATA1 bNAND_CTL(0x18) +#define NFMECCDATA2 bNAND_CTL(0x1c) +#define NFMECCDATA3 bNAND_CTL(0x20) +#define NFSECCDATA0 bNAND_CTL(0x24) +#define NFSECCDATA1 bNAND_CTL(0x28) +#define NFSTAT bNAND_CTL(0x2c) +#define NFESTAT0 bNAND_CTL(0x30) +#define NFESTAT1 bNAND_CTL(0x34) +#define NFMECC0 bNAND_CTL(0x38) +#define NFMECC1 bNAND_CTL(0x3c) +#define NFSECC bNAND_CTL(0x40) +#define NFSBLK bNAND_CTL(0x44) +#define NFEBLK bNAND_CTL(0x48) + + +/* + * NFCONF + */ +#define fNFCONF_AdvanceFlash Fld(1,22) +#define fNFCONF_TCEH Fld(6,16) +#define fNFCONF_TACLS Fld(3,12) +#define fNFCONF_TWRPH0 Fld(3,8) +#define fNFCONF_X16Device Fld(1,7) +#define fNFCONF_TWRPH1 Fld(3,4) +#define fNFCONF_Hardware_nCE Fld(1,3) +#define fNFCONF_BusWidth Fld(1,2) +#define fNFCONF_PageSize Fld(1,1) +#define fNFCONF_AddressCycle Fld(1,0) + +#define m1NFCONF_AdvanceFlash FMsk(fNFCONF_AdvanceFlash) +#define m1NFCONF_TCEH FMsk(fNFCONF_TCEH) +#define m1NFCONF_TACLS FMsk(fNFCONF_TACLS) +#define m1NFCONF_TWRPH0 FMsk(fNFCONF_TWRPH0) +#define m1NFCONF_X16Device FMsk(fNFCONF_X16Device) +#define m1NFCONF_TWRPH1 FMsk(fNFCONF_TWRPH1) +#define m1NFCONF_Hardware_nCE FMsk(fNFCONF_Hardware_nCE) +#define m1NFCONF_BusWidth FMsk(fNFCONF_BusWidth) +#define m1NFCONF_PageSize FMsk(fNFCONF_PageSize) +#define m1NFCONF_AddressCycle FMsk(fNFCONF_AddressCycle) + +#define m0NFCONF_AdvanceFlash (~m1NFCONF_AdvanceFlash) +#define m0NFCONF_TCEH (~m1NFCONF_TCEH) +#define m0NFCONF_TACLS (~m1NFCONF_TACLS) +#define m0NFCONF_TWRPH0 (~m1NFCONF_TWRPH0) +#define m0NFCONF_X16Device (~m1NFCONF_X16Device) +#define m0NFCONF_TWRPH1 (~m1NFCONF_TWRPH1) +#define m0NFCONF_Hardware_nCE (~m1NFCONF_Hardware_nCE) +#define m0NFCONF_BusWidth (~m1NFCONF_BusWidth) +#define m0NFCONF_PageSize (~m1NFCONF_PageSize) +#define m0NFCONF_AddressCycle (~m1NFCONF_AddressCycle) + +#define sNFCONF_TCEH(f_) (FInsrt(f_,fNFCONF_TCEH) & m1NFCONF_TCEH) +#define sNFCONF_TACLS(f_) (FInsrt(f_,fNFCONF_TACLS) & m1NFCONF_TACLS) +#define sNFCONF_TWRPH0(f_) (FInsrt(f_,fNFCONF_TWRPH0) & m1NFCONF_TWRPH0) +#define sNFCONF_TWRPH1(f_) (FInsrt(f_,fNFCONF_TWRPH1) & m1NFCONF_TWRPH1) +#define sNFCONF_Hardware_nCE(f_) (FInsrt(f_,fNFCONF_Hardware_nCE) & m1NFCONF_Hardware_nCE) + + +/* + * NFCONT + */ +#define fNFCONT_LdStrAddr Fld(12,16) +#define fNFCONT_EnbIllegalAccINT Fld(1,15) +#define fNFCONT_EnbLoadINT Fld(1,14) +#define fNFCONT_EnbStoreINT Fld(1,13) +#define fNFCONT_EnbRnBINT Fld(1,12) +#define fNFCONT_RnB_TransMode Fld(1,11) +#define fNFCONT_SpareECCLock Fld(1,10) +#define fNFCONT_MainECCLock Fld(1,9) +#define fNFCONT_InitECC Fld(1,8) +#define fNFCONT_Reg_nCE Fld(1,7) +#define fNFCONT_LoadPageSize Fld(3,4) +#define fNFCONT_Lock_tight Fld(1,3) +#define fNFCONT_Lock Fld(1,2) +#define fNFCONT_Mode Fld(2,0) + +#define m1NFCONT_LdStrAddr FMsk(fNFCONT_LdStrAddr) +#define m1NFCONT_EnbIllegalAccINT FMsk(fNFCONT_EnbIllegalAccINT) +#define m1NFCONT_EnbLoadINT FMsk(fNFCONT_EnbLoadINT) +#define m1NFCONT_EnbStoreINT FMsk(fNFCONT_EnbStoreINT) +#define m1NFCONT_EnbRnBINT FMsk(fNFCONT_EnbRnBINT) +#define m1NFCONT_RnB_TransMode FMsk(fNFCONT_RnB_TransMode) +#define m1NFCONT_SpareECCLock FMsk(fNFCONT_SpareECCLock) +#define m1NFCONT_MainECCLock FMsk(fNFCONT_MainECCLock) +#define m1NFCONT_InitECC FMsk(fNFCONT_InitECC) +#define m1NFCONT_Reg_nCE FMsk(fNFCONT_Reg_nCE) +#define m1NFCONT_LoadPageSize FMsk(fNFCONT_LoadPageSize) +#define m1NFCONT_Lock_tight FMsk(fNFCONT_Lock_tight) +#define m1NFCONT_Lock FMsk(fNFCONT_Lock) +#define m1NFCONT_Mode FMsk(fNFCONT_Mode) + +#define m0NFCONT_LdStrAddr (~m1NFCONT_LdStrAddr) +#define m0NFCONT_EnbIllegalAccINT (~m1NFCONT_EnbIllegalAccINT) +#define m0NFCONT_EnbLoadINT (~m1NFCONT_EnbLoadINT) +#define m0NFCONT_EnbStoreINT (~m1NFCONT_EnbStoreINT) +#define m0NFCONT_EnbRnBINT (~m1NFCONT_EnbRnBINT) +#define m0NFCONT_RnB_TransMode (~m1NFCONT_RnB_TransMode) +#define m0NFCONT_SpareECCLock (~m1NFCONT_SpareECCLock) +#define m0NFCONT_MainECCLock (~m1NFCONT_MainECCLock) +#define m0NFCONT_InitECC (~m1NFCONT_InitECC) +#define m0NFCONT_Reg_nCE (~m1NFCONT_Reg_nCE) +#define m0NFCONT_LoadPageSize (~m1NFCONT_LoadPageSize) +#define m0NFCONT_Lock_tight (~m1NFCONT_Lock_tight) +#define m0NFCONT_Lock (~m1NFCONT_Lock) +#define m0NFCONT_Mode (~m1NFCONT_Mode) + +#define sNFCONT_LdStrAddr(f_) (FInsrt(f_,fNFCONT_LdStrAddr) & m1NFCONT_LdStrAddr) +#define sNFCONT_EnbIllegalAccINT(f_) (FInsrt(f_,fNFCONT_EnbIllegalAccINT) & m1NFCONT_EnbIllegalAccINT) +#define sNFCONT_EnbLoadINT(f_) (FInsrt(f_,fNFCONT_EnbLoadINT) & m1NFCONT_EnbLoadINT) +#define sNFCONT_EnbStoreINT(f_) (FInsrt(f_,fNFCONT_EnbStoreINT) & m1NFCONT_EnbStoreINT) +#define sNFCONT_EnbRnBINT(f_) (FInsrt(f_,fNFCONT_EnbRnBINT) & m1NFCONT_EnbRnBINT) +#define sNFCONT_RnB_TransMode(f_) (FInsrt(f_,fNFCONT_RnB_TransMode) & m1NFCONT_RnB_TransMode) +#define sNFCONT_SpareECCLock(f_) (FInsrt(f_,fNFCONT_SpareECCLock) & m1NFCONT_SpareECCLock) +#define sNFCONT_MainECCLock(f_) (FInsrt(f_,fNFCONT_MainECCLock) & m1NFCONT_MainECCLock) +#define sNFCONT_InitECC(f_) (FInsrt(f_,fNFCONT_InitECC) & m1NFCONT_InitECC) +#define sNFCONT_Reg_nCE(f_) (FInsrt(f_,fNFCONT_Reg_nCE) & m1NFCONT_Reg_nCE) +#define sNFCONT_LoadPageSize(f_) (FInsrt(f_,fNFCONT_LoadPageSize) & m1NFCONT_LoadPageSize) +#define sNFCONT_Lock_tight(f_) (FInsrt(f_,fNFCONT_Lock_tight) & m1NFCONT_Lock_tight) +#define sNFCONT_Lock(f_) (FInsrt(f_,fNFCONT_Lock) & m1NFCONT_Lock) +#define sNFCONT_Mode(f_) (FInsrt(f_,fNFCONT_Mode) & m1NFCONT_Mode) + + +/* + * NFCMMD + */ +#define fNFCMMD_NFCMMD1 Fld(8,8) +#define fNFCMMD_NFCMMD0 Fld(8,0) + +#define m1NFCMMD_NFCMMD1 FMsk(fNFCMMD_NFCMMD1) +#define m1NFCMMD_NFCMMD0 FMsk(fNFCMMD_NFCMMD0) + +#define m0NFCMMD_NFCMMD1 (~m1NFCMMD_NFCMMD1) +#define m0NFCMMD_NFCMMD0 (~m1NFCMMD_NFCMMD0) + +#define sNFCMMD_NFCMMD1(f_) (FInsrt(f_,fNFCMMD_NFCMMD1) & m1NFCMMD_NFCMMD1) +#define sNFCMMD_NFCMMD0(f_) (FInsrt(f_,fNFCMMD_NFCMMD0) & m1NFCMMD_NFCMMD0) + + +/* + * NFADDR + */ +#define fNFADDR_NFADDR3 Fld(8,24) +#define fNFADDR_NFADDR2 Fld(8,16) +#define fNFADDR_NFADDR1 Fld(8,8) +#define fNFADDR_NFADDR0 Fld(8,0) + +#define m1NFADDR_NFADDR3 FMsk(fNFADDR_NFADDR3) +#define m1NFADDR_NFADDR2 FMsk(fNFADDR_NFADDR2) +#define m1NFADDR_NFADDR1 FMsk(fNFADDR_NFADDR1) +#define m1NFADDR_NFADDR0 FMsk(fNFADDR_NFADDR0) + +#define m0NFADDR_NFADDR3 (~m1NFADDR_NFADDR3) +#define m0NFADDR_NFADDR2 (~m1NFADDR_NFADDR2) +#define m0NFADDR_NFADDR1 (~m1NFADDR_NFADDR1) +#define m0NFADDR_NFADDR0 (~m1NFADDR_NFADDR0) + +#define sNFADDR_NFADDR3(f_) (FInsrt(f_,fNFADDR_NFADDR3) & m1NFADDR_NFADDR3) +#define sNFADDR_NFADDR2(f_) (FInsrt(f_,fNFADDR_NFADDR2) & m1NFADDR_NFADDR2) +#define sNFADDR_NFADDR1(f_) (FInsrt(f_,fNFADDR_NFADDR1) & m1NFADDR_NFADDR1) +#define sNFADDR_NFADDR0(f_) (FInsrt(f_,fNFADDR_NFADDR0) & m1NFADDR_NFADDR0) + + +/* + * NFDATA + */ +#define fNFDATA_NFDATA1 Fld(8,8) +#define fNFDATA_NFDATA0 Fld(8,0) + +#define m1NFDATA_NFDATA1 FMsk(fNFDATA_NFDATA1) +#define m1NFDATA_NFDATA0 FMsk(fNFDATA_NFDATA0) + +#define m0NFDATA_NFDATA1 (~m1NFDATA_NFDATA1) +#define m0NFDATA_NFDATA0 (~m1NFDATA_NFDATA0) + +#define sNFDATA_NFDATA1(f_) (FInsrt(f_,fNFDATA_NFDATA1) & m1NFDATA_NFDATA1) +#define sNFDATA_NFDATA0(f_) (FInsrt(f_,fNFDATA_NFDATA0) & m1NFDATA_NFDATA0) + + +/* + * NFMECCDATA0 + */ +#define fNFMECCDATA0_ECCData0_1 Fld(8,8) +#define fNFMECCDATA0_ECCData0_0 Fld(8,0) + +#define m1NFMECCDATA0_ECCData0_1 FMsk(fNFMECCDATA0_ECCData0_1) +#define m1NFMECCDATA0_ECCData0_0 FMsk(fNFMECCDATA0_ECCData0_0) + +#define m0NFMECCDATA0_ECCData0_1 (~m1NFMECCDATA0_ECCData0_1) +#define m0NFMECCDATA0_ECCData0_0 (~m1NFMECCDATA0_ECCData0_0) + +#define sNFMECCDATA0_ECCData0_1(f_) (FInsrt(f_,fNFMECCDATA0_ECCData0_1) & m1NFMECCDATA0_ECCData0_1) +#define sNFMECCDATA0_ECCData0_0(f_) (FInsrt(f_,fNFMECCDATA0_ECCData0_0) & m1NFMECCDATA0_ECCData0_0) + +/* + * NFMECCDATA1 + */ +#define fNFMECCDATA1_ECCData1_1 Fld(8,8) +#define fNFMECCDATA1_ECCData1_0 Fld(8,0) + +#define m1NFMECCDATA1_ECCData1_1 FMsk(fNFMECCDATA1_ECCData1_1) +#define m1NFMECCDATA1_ECCData1_0 FMsk(fNFMECCDATA1_ECCData1_0) + +#define m0NFMECCDATA1_ECCData1_1 (~m1NFMECCDATA1_ECCData1_1) +#define m0NFMECCDATA1_ECCData1_0 (~m1NFMECCDATA1_ECCData1_0) + +#define sNFMECCDATA1_ECCData1_1(f_) (FInsrt(f_,fNFMECCDATA1_ECCData1_1) & m1NFMECCDATA1_ECCData1_1) +#define sNFMECCDATA1_ECCData1_0(f_) (FInsrt(f_,fNFMECCDATA1_ECCData1_0) & m1NFMECCDATA1_ECCData1_0) + +/* + * NFMECCDATA2 + */ +#define fNFMECCDATA2_ECCData2_1 Fld(8,8) +#define fNFMECCDATA2_ECCData2_0 Fld(8,0) + +#define m1NFMECCDATA2_ECCData2_1 FMsk(fNFMECCDATA2_ECCData2_1) +#define m1NFMECCDATA2_ECCData2_0 FMsk(fNFMECCDATA2_ECCData2_0) + +#define m0NFMECCDATA2_ECCData2_1 (~m1NFMECCDATA2_ECCData2_1) +#define m0NFMECCDATA2_ECCData2_0 (~m1NFMECCDATA2_ECCData2_0) + +#define sNFMECCDATA2_ECCData2_1(f_) (FInsrt(f_,fNFMECCDATA2_ECCData2_1) & m1NFMECCDATA2_ECCData2_1) +#define sNFMECCDATA2_ECCData2_0(f_) (FInsrt(f_,fNFMECCDATA2_ECCData2_0) & m1NFMECCDATA2_ECCData2_0) + +/* + * NFMECCDATA3 + */ +#define fNFMECCDATA3_ECCData3_1 Fld(8,8) +#define fNFMECCDATA3_ECCData3_0 Fld(8,0) + +#define m1NFMECCDATA3_ECCData3_1 FMsk(fNFMECCDATA3_ECCData3_1) +#define m1NFMECCDATA3_ECCData3_0 FMsk(fNFMECCDATA3_ECCData3_0) + +#define m0NFMECCDATA3_ECCData3_1 (~m1NFMECCDATA3_ECCData3_1) +#define m0NFMECCDATA3_ECCData3_0 (~m1NFMECCDATA3_ECCData3_0) + +#define sNFMECCDATA3_ECCData3_1(f_) (FInsrt(f_,fNFMECCDATA3_ECCData3_1) & m1NFMECCDATA3_ECCData3_1) +#define sNFMECCDATA3_ECCData3_0(f_) (FInsrt(f_,fNFMECCDATA3_ECCData3_0) & m1NFMECCDATA3_ECCData3_0) + + +/* + * NFSECCDATA0 + */ +#define fNFSECCDATA0_ECCData0_1 Fld(8,8) +#define fNFSECCDATA0_ECCData0_0 Fld(8,0) + +#define m1NFSECCDATA0_ECCData0_1 FMsk(fNFSECCDATA0_ECCData0_1) +#define m1NFSECCDATA0_ECCData0_0 FMsk(fNFSECCDATA0_ECCData0_0) + +#define m0NFSECCDATA0_ECCData0_1 (~m1NFSECCDATA0_ECCData0_1) +#define m0NFSECCDATA0_ECCData0_0 (~m1NFSECCDATA0_ECCData0_0) + +#define sNFSECCDATA0_ECCData0_1(f_) (FInsrt(f_,fNFSECCDATA0_ECCData0_1) & m1NFSECCDATA0_ECCData0_1) +#define sNFSECCDATA0_ECCData0_0(f_) (FInsrt(f_,fNFSECCDATA0_ECCData0_0) & m1NFSECCDATA0_ECCData0_0) + +/* + * NFSECCDATA1 + */ +#define fNFSECCDATA1_ECCData1_1 Fld(8,8) +#define fNFSECCDATA1_ECCData1_0 Fld(8,0) + +#define m1NFSECCDATA1_ECCData1_1 FMsk(fNFSECCDATA1_ECCData1_1) +#define m1NFSECCDATA1_ECCData1_0 FMsk(fNFSECCDATA1_ECCData1_0) + +#define m0NFSECCDATA1_ECCData1_1 (~m1NFSECCDATA1_ECCData1_1) +#define m0NFSECCDATA1_ECCData1_0 (~m1NFSECCDATA1_ECCData1_0) + +#define sNFSECCDATA1_ECCData1_1(f_) (FInsrt(f_,fNFSECCDATA1_ECCData1_1) & m1NFSECCDATA1_ECCData1_1) +#define sNFSECCDATA1_ECCData1_0(f_) (FInsrt(f_,fNFSECCDATA1_ECCData1_0) & m1NFSECCDATA1_ECCData1_0) + + +/* + * NFSTAT + */ +#define fNFSTAT_IllegalAccess Fld(1,16) +#define fNFSTAT_AutoLoadDone Fld(1,15) +#define fNFSTAT_AutoStoreDone Fld(1,14) +#define fNFSTAT_RnB_TransDetect Fld(1,13) +#define fNFSTAT_Flash_nCE Fld(1,12) +#define fNFSTAT_Flash_RnB1 Fld(1,11) +#define fNFSTAT_Flash_RnB0 Fld(1,10) +#define fNFSTAT_STON_A2 Fld(10,0) + +#define m1NFSTAT_IllegalAccess FMsk(fNFSTAT_IllegalAccess) +#define m1NFSTAT_AutoLoadDone FMsk(fNFSTAT_AutoLoadDone) +#define m1NFSTAT_AutoStoreDone FMsk(fNFSTAT_AutoStoreDone) +#define m1NFSTAT_RnB_TransDetect FMsk(fNFSTAT_RnB_TransDetect) +#define m1NFSTAT_Flash_nCE FMsk(fNFSTAT_Flash_nCE) +#define m1NFSTAT_Flash_RnB1 FMsk(fNFSTAT_Flash_RnB1) +#define m1NFSTAT_Flash_RnB0 FMsk(fNFSTAT_Flash_RnB0) +#define m1NFSTAT_STON_A2 FMsk(fNFSTAT_STON_A2) + +#define m0NFSTAT_IllegalAccess (~m1NFSTAT_IllegalAccess) +#define m0NFSTAT_AutoLoadDone (~m1NFSTAT_AutoLoadDone) +#define m0NFSTAT_AutoStoreDone (~m1NFSTAT_AutoStoreDone) +#define m0NFSTAT_RnB_TransDetect (~m1NFSTAT_RnB_TransDetect) +#define m0NFSTAT_Flash_nCE (~m1NFSTAT_Flash_nCE) +#define m0NFSTAT_Flash_RnB1 (~m1NFSTAT_Flash_RnB1) +#define m0NFSTAT_Flash_RnB0 (~m1NFSTAT_Flash_RnB0) +#define m0NFSTAT_STON_A2 (~m1NFSTAT_STON_A2) + +#define sNFSTAT_IllegalAccess(f_) (FInsrt(f_,fNFSTAT_IllegalAccess) & m1NFSTAT_IllegalAccess) +#define sNFSTAT_AutoLoadDone(f_) (FInsrt(f_,fNFSTAT_AutoLoadDone) & m1NFSTAT_AutoLoadDone) +#define sNFSTAT_AutoStoreDone(f_) (FInsrt(f_,fNFSTAT_AutoStoreDone) & m1NFSTAT_AutoStoreDone) +#define sNFSTAT_RnB_TransDetect(f_) (FInsrt(f_,fNFSTAT_RnB_TransDetect) & m1NFSTAT_RnB_TransDetect) + + +/* + * NFESTAT0 + */ +#define fNFESTAT0_SErrorDataNo Fld(4,21) +#define fNFESTAT0_SErrorBitNo Fld(3,18) +#define fNFESTAT0_MErrorDataNo Fld(11,7) +#define fNFESTAT0_MErrorBitNo Fld(3,4) +#define fNFESTAT0_SpareError Fld(2,2) +#define fNFESTAT0_MainError Fld(2,0) + +#define m1NFESTAT0_SErrorDataNo FMsk(fNFESTAT0_SErrorDataNo) +#define m1NFESTAT0_SErrorBitNo FMsk(fNFESTAT0_SErrorBitNo) +#define m1NFESTAT0_MErrorDataNo FMsk(fNFESTAT0_MErrorDataNo) +#define m1NFESTAT0_MErrorBitNo FMsk(fNFESTAT0_MErrorBitNo) +#define m1NFESTAT0_SpareError FMsk(fNFESTAT0_SpareError) +#define m1NFESTAT0_MainError FMsk(fNFESTAT0_MainError) + +#define m0NFESTAT0_SErrorDataNo (~m1NFESTAT0_SErrorDataNo) +#define m0NFESTAT0_SErrorBitNo (~m1NFESTAT0_SErrorBitNo) +#define m0NFESTAT0_MErrorDataNo (~m1NFESTAT0_MErrorDataNo) +#define m0NFESTAT0_MErrorBitNo (~m1NFESTAT0_MErrorBitNo) +#define m0NFESTAT0_SpareError (~m1NFESTAT0_SpareError) +#define m0NFESTAT0_MainError (~m1NFESTAT0_MainError) + +#define sNFESTAT0_SErrorDataNo(f_) (FInsrt(f_,fNFESTAT0_SErrorDataNo) & m1NFESTAT0_SErrorDataNo) +#define sNFESTAT0_SErrorBitNo(f_) (FInsrt(f_,fNFESTAT0_SErrorBitNo) & m1NFESTAT0_SErrorBitNo) +#define sNFESTAT0_MErrorDataNo(f_) (FInsrt(f_,fNFESTAT0_MErrorDataNo) & m1NFESTAT0_MErrorDataNo) +#define sNFESTAT0_MErrorBitNo(f_) (FInsrt(f_,fNFESTAT0_MErrorBitNo) & m1NFESTAT0_MErrorBitNo) +#define sNFESTAT0_SpareError(f_) (FInsrt(f_,fNFESTAT0_SpareError) & m1NFESTAT0_SpareError) +#define sNFESTAT0_MainError(f_) (FInsrt(f_,fNFESTAT0_MainError) & m1NFESTAT0_MainError) + +/* + * NFESTAT1 + */ +#define fNFESTAT1_SErrorDataNo Fld(4,21) +#define fNFESTAT1_SErrorBitNo Fld(3,18) +#define fNFESTAT1_MErrorDataNo Fld(11,7) +#define fNFESTAT1_MErrorBitNo Fld(3,4) +#define fNFESTAT1_SpareError Fld(2,2) +#define fNFESTAT1_MainError Fld(2,0) + +#define m1NFESTAT1_SErrorDataNo FMsk(fNFESTAT1_SErrorDataNo) +#define m1NFESTAT1_SErrorBitNo FMsk(fNFESTAT1_SErrorBitNo) +#define m1NFESTAT1_MErrorDataNo FMsk(fNFESTAT1_MErrorDataNo) +#define m1NFESTAT1_MErrorBitNo FMsk(fNFESTAT1_MErrorBitNo) +#define m1NFESTAT1_SpareError FMsk(fNFESTAT1_SpareError) +#define m1NFESTAT1_MainError FMsk(fNFESTAT1_MainError) + +#define m0NFESTAT1_SErrorDataNo (~m1NFESTAT1_SErrorDataNo) +#define m0NFESTAT1_SErrorBitNo (~m1NFESTAT1_SErrorBitNo) +#define m0NFESTAT1_MErrorDataNo (~m1NFESTAT1_MErrorDataNo) +#define m0NFESTAT1_MErrorBitNo (~m1NFESTAT1_MErrorBitNo) +#define m0NFESTAT1_SpareError (~m1NFESTAT1_SpareError) +#define m0NFESTAT1_MainError (~m1NFESTAT1_MainError) + +#define sNFESTAT1_SErrorDataNo(f_) (FInsrt(f_,fNFESTAT1_SErrorDataNo) & m1NFESTAT1_SErrorDataNo) +#define sNFESTAT1_SErrorBitNo(f_) (FInsrt(f_,fNFESTAT1_SErrorBitNo) & m1NFESTAT1_SErrorBitNo) +#define sNFESTAT1_MErrorDataNo(f_) (FInsrt(f_,fNFESTAT1_MErrorDataNo) & m1NFESTAT1_MErrorDataNo) +#define sNFESTAT1_MErrorBitNo(f_) (FInsrt(f_,fNFESTAT1_MErrorBitNo) & m1NFESTAT1_MErrorBitNo) +#define sNFESTAT1_SpareError(f_) (FInsrt(f_,fNFESTAT1_SpareError) & m1NFESTAT1_SpareError) +#define sNFESTAT1_MainError(f_) (FInsrt(f_,fNFESTAT1_MainError) & m1NFESTAT1_MainError) + + +/* + * NFMECC0 + */ +#define fNFMECC0_MECC0_3 Fld(8,24) +#define fNFMECC0_MECC0_2 Fld(8,16) +#define fNFMECC0_MECC0_1 Fld(8,8) +#define fNFMECC0_MECC0_0 Fld(8,0) + +#define m1NFMECC0_MECC0_3 FMsk(fNFMECC0_MECC0_3) +#define m1NFMECC0_MECC0_2 FMsk(fNFMECC0_MECC0_2) +#define m1NFMECC0_MECC0_1 FMsk(fNFMECC0_MECC0_1) +#define m1NFMECC0_MECC0_0 FMsk(fNFMECC0_MECC0_0) + +#define m0NFMECC0_MECC0_3 (~m1NFMECC0_MECC0_3) +#define m0NFMECC0_MECC0_2 (~m1NFMECC0_MECC0_2) +#define m0NFMECC0_MECC0_1 (~m1NFMECC0_MECC0_1) +#define m0NFMECC0_MECC0_0 (~m1NFMECC0_MECC0_0) + +/* + * NFMECC1 + */ +#define fNFMECC1_MECC1_3 Fld(8,24) +#define fNFMECC1_MECC1_2 Fld(8,16) +#define fNFMECC1_MECC1_1 Fld(8,8) +#define fNFMECC1_MECC1_0 Fld(8,0) + +#define m1NFMECC1_MECC1_3 FMsk(fNFMECC1_MECC1_3) +#define m1NFMECC1_MECC1_2 FMsk(fNFMECC1_MECC1_2) +#define m1NFMECC1_MECC1_1 FMsk(fNFMECC1_MECC1_1) +#define m1NFMECC1_MECC1_0 FMsk(fNFMECC1_MECC1_0) + +#define m0NFMECC1_MECC1_3 (~m1NFMECC1_MECC1_3) +#define m0NFMECC1_MECC1_2 (~m1NFMECC1_MECC1_2) +#define m0NFMECC1_MECC1_1 (~m1NFMECC1_MECC1_1) +#define m0NFMECC1_MECC1_0 (~m1NFMECC1_MECC1_0) + + +/* + * NFSECC + */ +#define fNFSECC_SECC1_1 Fld(8,24) +#define fNFSECC_SECC1_0 Fld(8,16) +#define fNFSECC_SECC0_1 Fld(8,8) +#define fNFSECC_SECC0_0 Fld(8,0) + +#define m1NFSECC_SECC1_1 FMsk(fNFSECC_SECC1_1) +#define m1NFSECC_SECC1_0 FMsk(fNFSECC_SECC1_0) +#define m1NFSECC_SECC0_1 FMsk(fNFSECC_SECC0_1) +#define m1NFSECC_SECC0_0 FMsk(fNFSECC_SECC0_0) + +#define m0NFSECC_SECC1_1 (~m1NFSECC_SECC1_1) +#define m0NFSECC_SECC1_0 (~m1NFSECC_SECC1_0) +#define m0NFSECC_SECC0_1 (~m1NFSECC_SECC0_1) +#define m0NFSECC_SECC0_0 (~m1NFSECC_SECC0_0) + + +/* + * NFSBLK + */ +#define fNFSBLK_SBLK_ADDR2 Fld(8,16) +#define fNFSBLK_SBLK_ADDR1 Fld(8,8) +#define fNFSBLK_SBLK_ADDR0 Fld(8,0) + +#define m1NFSBLK_SBLK_ADDR2 FMsk(fNFSBLK_SBLK_ADDR2) +#define m1NFSBLK_SBLK_ADDR1 FMsk(fNFSBLK_SBLK_ADDR1) +#define m1NFSBLK_SBLK_ADDR0 FMsk(fNFSBLK_SBLK_ADDR0) + +#define m0NFSBLK_SBLK_ADDR2 (~m1NFSBLK_SBLK_ADDR2) +#define m0NFSBLK_SBLK_ADDR1 (~m1NFSBLK_SBLK_ADDR1) +#define m0NFSBLK_SBLK_ADDR0 (~m1NFSBLK_SBLK_ADDR0) + +#define sNFSBLK_SBLK_ADDR2(f_) (FInsrt(f_,fNFSBLK_SBLK_ADDR2) & m1NFSBLK_SBLK_ADDR2) +#define sNFSBLK_SBLK_ADDR1(f_) (FInsrt(f_,fNFSBLK_SBLK_ADDR1) & m1NFSBLK_SBLK_ADDR1) +#define sNFSBLK_SBLK_ADDR0(f_) (FInsrt(f_,fNFSBLK_SBLK_ADDR0) & m1NFSBLK_SBLK_ADDR0) + +/* + * NFEBLK + */ +#define fNFEBLK_EBLK_ADDR2 Fld(8,16) +#define fNFEBLK_EBLK_ADDR1 Fld(8,8) +#define fNFEBLK_EBLK_ADDR0 Fld(8,0) + +#define m1NFEBLK_EBLK_ADDR2 FMsk(fNFEBLK_EBLK_ADDR2) +#define m1NFEBLK_EBLK_ADDR1 FMsk(fNFEBLK_EBLK_ADDR1) +#define m1NFEBLK_EBLK_ADDR0 FMsk(fNFEBLK_EBLK_ADDR0) + +#define m0NFEBLK_EBLK_ADDR2 (~m1NFEBLK_EBLK_ADDR2) +#define m0NFEBLK_EBLK_ADDR1 (~m1NFEBLK_EBLK_ADDR1) +#define m0NFEBLK_EBLK_ADDR0 (~m1NFEBLK_EBLK_ADDR0) + +#define sNFEBLK_EBLK_ADDR2(f_) (FInsrt(f_,fNFEBLK_EBLK_ADDR2) & m1NFEBLK_EBLK_ADDR2) +#define sNFEBLK_EBLK_ADDR1(f_) (FInsrt(f_,fNFEBLK_EBLK_ADDR1) & m1NFEBLK_EBLK_ADDR1) +#define sNFEBLK_EBLK_ADDR0(f_) (FInsrt(f_,fNFEBLK_EBLK_ADDR0) & m1NFEBLK_EBLK_ADDR0) + +#endif /* _S3C24A0_NAND_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/smdk.h b/include/asm-arm/arch-s3c24a0/smdk.h new file mode 100644 index 00000000..cb111b75 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/smdk.h @@ -0,0 +1,144 @@ +/* + * include/asm-arm/arch-s3c24a0/smdk.h + * + * Changes + * + * 2004/06/10 CPLD IDE code added + * + */ + +#ifndef _SMDK24A0_H_ +#define _SMDK24A0_H_ + +/* Externl clock frequency used by CPU */ +#define FIN 12000000 + +/* + * on SMDK24A0, + * there are so many cross-interference jumpers (h/w switch). + */ + +/* + * This is for SPJ Board - hcyun + + XgpIO0 <------ EINT0 + XgpIO1 <------ EINT1 + XgpIO2 <------ SD_INT + XgpIO3 ------> XGPIO_nSS <-- not used + XgpIO4 ------> LED0 + XgpIO5 ------> LED1 + XgpIO6 ------> LED2 + XgpIO7 ------> LED3 + XgpIO8 <-----> + XgpIO9 ------> + XgpIO10 <------ EINT10 <-- not used + XgpIO11 <------ EINT11 <-- not used + XgpIO12 <------ MODEM_INT <-- not used + XgpIO13 <------ ETHER_INT + XgpIO14 <------ SMC_INT <-- not used + XgpIO15 ------> SMC_WP <-- l3-bit-elfin.c I2C??? l3 bus + XgpIO16 <------ SPJ IDE <-- IDE & l3-bit-elfin.c I2C??? l3 bus + XgpIO17 <------ SPJ USB <-- USB + XgpIO18 <-----> KP_ROW0 + XgpIO19 <-----> KP_ROW1 <-- s3c24a0_keyif.c + XgpIO20 <-----> KP_ROW2 <-- s3c24a0_keyif.c + XgpIO21 <-----> KP_ROW3 + XgpIO22 <-----> KP_ROW4 + XgpIO23 <-----> KP_COL0 + XgpIO24 <-----> KP_COL1 + XgpIO25 <-----> KP_COL2 + XgpIO26 <-----> KP_COL3 + XgpIO27 <-----> KP_COL4 + XgpIO28 <-----> + XgpIO29 <-----> + XgpIO30 <-----> + XgpIO31 <-----> + + * + */ + +#define SMDK_SMC_WP GPIO_15 /* O : SMC Write-Protect */ + +#define SMDK_CAM_SCL GPIO_9 /* O : Camera I2C/SCCB clock */ +#define SMDK_CAM_SDA GPIO_8 /* I/O : Camera I2C/SCCB data */ +#define SMDK_LED7 GPIO_7 /* O : LED3, Low-Active */ +#define SMDK_LED6 GPIO_6 /* O : LED2, LOw-Active */ +#define SMDK_LED5 GPIO_5 /* O : LED1, LOw-Active */ +#define SMDK_LED4 GPIO_4 /* O : LED0, Low-Active */ + +/* GPIO buttons. EINT 0,1,10,11 */ +#define SMDK_EINT0_IRQ IRQ_EINT0 +#define SMDK_EINT1_IRQ IRQ_EINT1 +#define SMDK_EINT10_IRQ IRQ_EINT10 +#define SMDK_EINT11_IRQ IRQ_EINT11 +#define SMDK_EINT0_GPIO GPIO_0 +#define SMDK_EINT1_GPIO GPIO_1 +#define SMDK_EINT10_GPIO GPIO_10 +#define SMDK_EINT11_GPIO GPIO_11 + +#ifdef CONFIG_MMU + #define SROM_BANK1_PBASE 0x04000000 + #define SROM_BANK1_VBASE 0xf0000000 +#else /* UCLINUX */ + #define SROM_BANK1_PBASE 0x04000000 + #define SROM_BANK1_VBASE 0x04000000 +#endif /* CONFIG_MMU */ + +#ifndef __ASSEMBLY__ +/* + * BANK1 control for cs89x0, IDE, USB2.0 - hcyun + */ +typedef struct { + unsigned long bw; + unsigned long bc; +} bank_param_t; + +#define B1_STATE_NONE -1 +#define B1_IDE_PIO0 0 +#define B1_IDE_PIO4 1 +#define B1_CS89x0 2 +#define B1_USB2 3 +#define B1_STATE_LIMIT 3 + +#endif + + +/* CPLD IDE - hcyun + * 0x07000000 [0] : IDE reset + * [1] : 0 - USB, 1 - IDE + */ + +#define SMDK_CPLD_IDE_IRQ_GPIO GPIO_4 +#define SMDK_CPLD_IDE_IRQ IRQ_EINT4 +#define SMDK_CPLD_IDE_VIO (SROM_BANK1_VBASE + 0x03000000) // 0xf3000000 +#define SMDK_CPLD_IDE_PIO (SROM_BANK1_PBASE + 0x03000000) // 0x04000000 + + +/* CPLD USB - hcyun + * 0x06000000 [0] : USB reset + */ +/*seo 20040616 */ +#define SMDK_CPLD_USB_IRQ_GPIO GPIO_5 +#define SMDK_CPLD_USB_IRQ IRQ_EINT5 +#define SMDK_CPLD_USB_VIO (SROM_BANK1_VBASE + 0x02000000) +#define SMDK_CPLD_USB_PIO (SROM_BANK1_PBASE + 0x02000000) + + +/* CS8900A */ +#define SMDK_CS8900_IRQ_GPIO GPIO_13 +#define SMDK_CS8900_IRQ IRQ_EINT13 +#define SMDK_CS8900_VIO SROM_BANK1_VBASE +#define SMDK_CS8900_PIO (SROM_BANK1_PBASE | (1<<24)) + +/* IRDA */ +#define SMDK_IRDA_SDBW (GPIO_MODE_IrDA_SDBW | GPIO_16 | GPIO_PULLUP_DIS) +#define SMDK_IRDA_TXD (GPIO_MODE_IrDA_TXD | GPIO_17 | GPIO_PULLUP_DIS) +#define SMDK_IRDA_RXD (GPIO_MODE_IrDA_RXD | GPIO_18 | GPIO_PULLUP_DIS) + +/* UART */ +#define SMDK_UART1_nCTS (GPIO_MODE_UART | GPIO_28 | GPIO_PULLUP_DIS) +#define SMDK_UART1_nRTS (GPIO_MODE_UART | GPIO_29 | GPIO_PULLUP_DIS) +#define SMDK_UART1_TXD (GPIO_MODE_UART | GPIO_30 | GPIO_PULLUP_DIS) +#define SMDK_UART1_RXD (GPIO_MODE_UART | GPIO_31 | GPIO_PULLUP_DIS) + +#endif /* _SMDK24A0_H_ */ diff --git a/include/asm-arm/arch-s3c24a0/system.h b/include/asm-arm/arch-s3c24a0/system.h new file mode 100644 index 00000000..45a6e518 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/system.h @@ -0,0 +1,31 @@ +/* + * include/asm-arm/arch-s3c24a0/system.h + * + * $Id: system.h,v 1.3 2006/12/12 13:13:07 gerg Exp $ + * + * 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 + +static inline +void arch_idle(void) +{ + /* TODO */ + cpu_do_idle(/*0*/); +} + +static inline +void arch_reset(char mode) +{ + if (mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + WTCNT = 0x100; + WTDAT = 0x100; + WTCON = 0x8021; + } +} diff --git a/include/asm-arm/arch-s3c24a0/time.h b/include/asm-arm/arch-s3c24a0/time.h new file mode 100644 index 00000000..9e73f036 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/time.h @@ -0,0 +1,16 @@ +/* + * include/asm-arm/arch-s3c24a0/time.h + * + * $Id: time.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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 linux/include/asm-arm/arch-s3c2410/time.h + */ + +#include /* for mktime() */ +#include /* struct rtc_time */ +#include "clocks.h" + diff --git a/include/asm-arm/arch-s3c24a0/timex.h b/include/asm-arm/arch-s3c24a0/timex.h new file mode 100644 index 00000000..55859014 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/timex.h @@ -0,0 +1,27 @@ +/* + * include/asm-arm/arch-s3c24a0/timex.h + * + * $Id: timex.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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 linux/include/asm-arm/arch-s3c2410/timex.h + */ + + +/* If a value of TCFG1 is a, a value of divider is 2 << a */ +#define CLK_DIVIDER 2 +/* a value of TCFG0_PRE1 */ +#define CLK_PRESCALE 15 + +#include + +/* PCLK */ +// #define CLK_INPUT elfin_get_bus_clk(GET_PCLK) +#define CLK_INPUT 51000000 /* 204-102-51 MHz */ + +/*#define CLOCK_TICK_RATE 1562500 */ +#define CLOCK_TICK_RATE (CLK_INPUT / (CLK_PRESCALE ) / CLK_DIVIDER) +#define CLOCK_TICK_FACTOR 80 diff --git a/include/asm-arm/arch-s3c24a0/uncompress-jtag.h b/include/asm-arm/arch-s3c24a0/uncompress-jtag.h new file mode 100644 index 00000000..e5960b93 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/uncompress-jtag.h @@ -0,0 +1,58 @@ +/* + * linux/include/asm-armnommu/arch-s5c7375/uncompress.h + * + * Copyright (C) 2004 Hyok S. Choi, Samsung Electronics Co.,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 + */ +#include + +#ifndef __UNCOMPRESS_H__ +#define __UNCOMPRESS_H__ + +/* + * just use DCC JTAG1 port + */ +static inline void puts(const char *s) +{ + dcc_puts(s); +} + +static void puts_hex(unsigned long i) +{ + char lhex_buf[]="0x00000000"; + unsigned long ii,v; + + for(ii=9;ii>1;ii--) + { + v=(((0x0000000F << ((9-ii)*4)) & i) >> ((9-ii)*4)); + if(v>9) + lhex_buf[ii]=(char)('A'+v-10); + else + lhex_buf[ii]=(char)('0'+v); + } + + dcc_puts(lhex_buf); +} + + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif diff --git a/include/asm-arm/arch-s3c24a0/uncompress.h b/include/asm-arm/arch-s3c24a0/uncompress.h new file mode 100644 index 00000000..7c373c74 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/uncompress.h @@ -0,0 +1,59 @@ +/* + * include/asm-arm/arch-s3c24a0/uncompress.h + * + * $Id: uncompress.h,v 1.3 2006/12/12 13:13:07 gerg Exp $ + * + * 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. + */ + + +/* + * The following code assumes the serial port has already been + * initialized by the bootloader. We use only UART1 on S3C24xx + */ + +#define ULCON 0x0 +#define UTRSTAT 0x10 +#define UTXH 0x20 +#define UTRSTAT_TX_EMPTY (1 << 2) + +#define UART0 0x44400000 +#define UART1 0x44404000 + +#define UART(x) (*(volatile unsigned long *)(serial_port + (x))) + +static void putstr(const char *s) +{ + unsigned long serial_port; + + do { + serial_port = UART0; + if (UART(ULCON) == 0x3) break; + serial_port = UART1; + if (UART(ULCON) == 0x3) break; + } while (0); + + for (; *s; s++) { + /* wait */ + while (!(UART(UTRSTAT) & UTRSTAT_TX_EMPTY)); + + /* send the character out. */ + UART(UTXH) = *s; + + /* if a LF, also do CR... */ + if (*s == 10) { + while (!(UART(UTRSTAT) & UTRSTAT_TX_EMPTY)); + + UART(UTXH) = 13; + } + } +} + + +/* + * Nothing to do for these + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-s3c24a0/vmalloc.h b/include/asm-arm/arch-s3c24a0/vmalloc.h new file mode 100644 index 00000000..72078361 --- /dev/null +++ b/include/asm-arm/arch-s3c24a0/vmalloc.h @@ -0,0 +1,24 @@ +/* + * include/asm-arm/arch-s3c24a0/vmalloc.h + * + * $Id: vmalloc.h,v 1.2 2005/11/28 03:55:11 gerg Exp $ + * + * 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 linux/include/asm-arm/arch-pxa/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff --git a/include/asm-arm/arch-s3c3410/dma.h b/include/asm-arm/arch-s3c3410/dma.h new file mode 100644 index 00000000..9dad9836 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/dma.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/dma.h + * + * Copyright (C) 2003 Hyok S. Choi + */ + +#include +#include + +#ifndef __ASM_S3C3410_ARCH_DMA_H +#define __ASM_S3C3410_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x03000000 +/* + * The S3C3410 has 2 internal DMA channels. + */ +#define MAX_DMA_CHANNELS 2 +#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ + +#endif /* _ASM_S3C3410_ARCH_DMA_H */ + diff --git a/include/asm-arm/arch-s3c3410/entry-macro.S b/include/asm-arm/arch-s3c3410/entry-macro.S new file mode 100644 index 00000000..91a4b0d5 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/entry-macro.S @@ -0,0 +1,38 @@ +/* + * arch/armnommu/mach-s3c3410/entry-macro.S + * + * Copyright (C) 2003 Hyok S. Choi + * Samsung Electronics Co.,Ltd. + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + */ + +#if defined(CONFIG_ARCH_S3C3410) + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + ldr \irqstat, =(S3C3410X_INTPND) @ load address of interrupt pending +@ ldr \irqstat, [\irqstat] @ register INTPND + ldr \irqnr, [\irqstat] @ \irqnr = INTPND + add \irqstat, \irqstat, #(S3C3410X_INTMSK-S3C3410X_INTPND) + ldr \irqstat, [\irqstat] @ \irqstat = INTMSK + and \irqstat, \irqnr, \irqstat @ \irqstat = (INTPND & INTMSK) + + mov \irqnr, #0 +1001: + tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #NR_IRQS + bcc 1001b +1002: /* EQ will be set if we reach 32 */ + .endm + + .macro irq_prio_table + .endm +#endif diff --git a/include/asm-arm/arch-s3c3410/hardware.h b/include/asm-arm/arch-s3c3410/hardware.h new file mode 100644 index 00000000..c404f65e --- /dev/null +++ b/include/asm-arm/arch-s3c3410/hardware.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-s3c3410/hardware.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#ifndef __ASSEMBLY__ + +#define HARD_RESET_NOW() + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (1) + +#endif + +#endif /* END OF __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-s3c3410/io.h b/include/asm-arm/arch-s3c3410/io.h new file mode 100644 index 00000000..5615d169 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/io.h @@ -0,0 +1,67 @@ +/* + * linux/include/asm-arm/arch-s3c3410/io.h + * + * Copyright (C) 2003 Thomas Eschenbacher + * Modified by Hyok S. Choi + * + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + /* Used in kernel/resource.c */ + +/* + * We have the this routine to use usb host device driver + */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + + +/* + * These macros were copied from arch/armnommu/io.h and are used instead + * of the definitions found there, because we want to do 16/32 bit i/o + * without byte swapping. + * --the + */ + +#undef __io + +#ifndef __iob + #define __iob(a) __io(a) +#endif + +#define outb(v,p) __raw_writeb(v, p) +#define outw(v,p) __raw_writew(v, p) +#define outl(v,p) __raw_writel(v, p) + +#define inb(p) ({ unsigned int __v = __raw_readb(p); __v; }) +#define inw(p) ({ unsigned int __v = __raw_readw(p); __v; }) +#define inl(p) ({ unsigned int __v = __raw_readl(p); __v; }) + +#define outsb(p,d,l) __raw_writesb(p, d, l) +#define outsw(p,d,l) __raw_writesw(p, d, l) +#define outsl(p,d,l) __raw_writesl(p, d, l) + +#define insb(p,d,l) __raw_readsb(p, d, l) +#define insw(p,d,l) __raw_readsw(p, d, l) +#define insl(p,d,l) __raw_readsl(p, d, l) + +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) (1) + + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-s3c3410/irq.h b/include/asm-arm/arch-s3c3410/irq.h new file mode 100644 index 00000000..26ec8232 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/irq.h @@ -0,0 +1,24 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/irq.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#ifndef __S3C3410_irq_h +#define __S3C3410_irq_h + +#include +#include +#include +#include + +extern unsigned int fixup_irq(int i); + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void s3c3410_init_irq(void); + +#define irq_init_irq s3c3410_init_irq + +#endif diff --git a/include/asm-arm/arch-s3c3410/irqs.h b/include/asm-arm/arch-s3c3410/irqs.h new file mode 100644 index 00000000..5e6aefb4 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/irqs.h @@ -0,0 +1,48 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/irqs.h + * + * 2003 Thomas Eschenbacher + * + * All IRQ numbers of the S3C3410X CPUs. + * + */ + +#ifndef __S3C3410_irqs_h +#define __S3C3410_irqs_h 1 + +#define NR_IRQS 32 + +#define S3C3410X_INTERRUPT_EINT0 0 /* External int. 0 */ +#define S3C3410X_INTERRUPT_EINT1 1 /* External int. 1 */ +#define S3C3410X_INTERRUPT_URX 2 /* UART receive */ +#define S3C3410X_INTERRUPT_UTX 3 /* UART transmit */ +#define S3C3410X_INTERRUPT_UERR 4 /* UART error */ +#define S3C3410X_INTERRUPT_DMA0 5 /* DMA 0 */ +#define S3C3410X_INTERRUPT_DMA1 6 /* DMA 1 */ +#define S3C3410X_INTERRUPT_TOF0 7 /* Timer 0 overflow */ +#define S3C3410X_INTERRUPT_TMC0 8 /* Timer 0 match/capture */ +#define S3C3410X_INTERRUPT_TOF1 9 /* Timer 1 overflow */ +#define S3C3410X_INTERRUPT_TMC1 10 /* Timer 1 match/capture */ +#define S3C3410X_INTERRUPT_TOF2 11 /* Timer 2 overflow */ +#define S3C3410X_INTERRUPT_TMC2 12 /* Timer 2 match/capture */ +#define S3C3410X_INTERRUPT_TOF3 13 /* Timer 3 overflow */ +#define S3C3410X_INTERRUPT_TMC3 14 /* Timer 3 match/capture */ +#define S3C3410X_INTERRUPT_TOF4 15 /* Timer 4 overflow */ +#define S3C3410X_INTERRUPT_TMC4 16 /* Timer 4 match/capture */ +#define S3C3410X_INTERRUPT_BT 17 /* Basic Timer */ +#define S3C3410X_INTERRUPT_SIO0 18 /* SIO 0 */ +#define S3C3410X_INTERRUPT_SIO1 19 /* SIO 1 */ +#define S3C3410X_INTERRUPT_IIC 20 /* IIC */ +#define S3C3410X_INTERRUPT_RTCA 21 /* RTC alarm */ +#define S3C3410X_INTERRUPT_RTCT 22 /* RTC time (SEC/MIN/HOUR) */ +#define S3C3410X_INTERRUPT_TF 23 /* Timer4 FIFO interrupt */ +#define S3C3410X_INTERRUPT_EINT2 24 /* External int. 2 */ +#define S3C3410X_INTERRUPT_EINT3 25 /* External int. 3 */ +#define S3C3410X_INTERRUPT_EINT4567 26 /* External int. 4/5/6/7 */ +#define S3C3410X_INTERRUPT_ADC 27 /* ADC interrupt */ +#define S3C3410X_INTERRUPT_EINT8 28 /* External int. 8 */ +#define S3C3410X_INTERRUPT_EINT9 29 /* External int. 9 */ +#define S3C3410X_INTERRUPT_EINT10 30 /* External int. 10 */ +#define S3C3410X_INTERRUPT_EINT11 31 /* External int. 11 */ + +#endif /* End of __irqs_h */ diff --git a/include/asm-arm/arch-s3c3410/keyboard.h b/include/asm-arm/arch-s3c3410/keyboard.h new file mode 100644 index 00000000..b21137d5 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/keyboard.h @@ -0,0 +1,21 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/keyboard.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + * just a cite from other architecture :) + */ +#ifndef __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H +#define __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) +#define kbd_translate(sc,kcp,rm) ({ *(kcp) = (sc); 1; }) +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) +#define kbd_init_hw() +#define kbd_enable_irq() +#define kbd_disable_irq() + +#endif /* __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H */ diff --git a/include/asm-arm/arch-s3c3410/memory.h b/include/asm-arm/arch-s3c3410/memory.h new file mode 100644 index 00000000..102a905e --- /dev/null +++ b/include/asm-arm/arch-s3c3410/memory.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-s3c3410/memory.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-s3c3410/param.h b/include/asm-arm/arch-s3c3410/param.h new file mode 100644 index 00000000..8a1d92b2 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/param.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-s3c3410/s3c3410.h b/include/asm-arm/arch-s3c3410/s3c3410.h new file mode 100644 index 00000000..9b8d1ee1 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/s3c3410.h @@ -0,0 +1,384 @@ +/* + * linux/include/asm-arm/arch-s3c3410/s3c3410.h + * + * Special function registers of the Samsung S3C3410X + * + * (C) 2003 sympat GmbH + * by Thomas Eschenbacher + * + */ + +#ifndef __ASM_ARCH_S3C3410_H +#define __ASM_ARCH_S3C3410_H + +#define S3C3410_MEM_SIZE (CONFIG_DRAM_SIZE) +#define MEM_SIZE S3C3410_MEM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE + +/* Address offset for accessing external memory uncached (A27=1) */ +#define S3C3410X_UNCACHED 0x08000000 /* (1 << 27) */ + +/* + * SFR Base Address + */ +#define S3C3410X_BASE 0x07FF0000 + +/* ************************ */ +/* System Manager Registers */ +/* ************************ */ +#define S3C3410X_SYSCFG (S3C3410X_BASE+0x1000) /* System Configuration */ + +#define S3C3410X_SYSCFG_ST 0x00000001 /* Stall enable */ +#define S3C3410X_SYSCFG_CE 0x00000002 /* Cache enable*/ +#define S3C3410X_SYSCFG_WE 0x00000004 /* Write Buffer enable */ +#define S3C3410X_SYSCFG_SFRSA 0x00007FF0 /* SYSCFG Address (SFR Start Address) */ + +#define S3C3410X_SYSCFG_CM_MASK 0x00018000 /* Cache Mode (MASK) */ +#define S3C3410X_SYSCFG_CM_22 0x00000000 /* (Cache Mode) 2k Cache / 2k SRAM */ +#define S3C3410X_SYSCFG_CM_CACHE 0x00008000 /* (Cache Mode) 4k Cache */ +#define S3C3410X_SYSCFG_CM_SRAM 0x00010000 /* (Cache Mode) 4k SRAM */ + +#define S3C3410X_SYSCFG_AME 0x00020000 /* Address Mux Enable */ +#define S3C3410X_SYSCFG_MT0_RFS 0x00000000 /* Memory Type 0 ROM/Flash/SRAM */ +#define S3C3410X_SYSCFG_MT0_FP 0x00040000 /* Memory Type 0 FP DRAM */ +#define S3C3410X_SYSCFG_MT0_EDO 0x00080000 /* Memory Type 0 EDO DRAM */ +#define S3C3410X_SYSCFG_MT0_SD 0x000C0000 /* Memory Type 0 Sync. DRAM */ +#define S3C3410X_SYSCFG_MT1_RFS 0x00000000 /* Memory Type 1 ROM/Flash/SRAM */ +#define S3C3410X_SYSCFG_MT1_FP 0x00100000 /* Memory Type 1 FP DRAM */ +#define S3C3410X_SYSCFG_MT1_EDO 0x00200000 /* Memory Type 1 EDO DRAM */ +#define S3C3410X_SYSCFG_MT1_SD 0x00300000 /* Memory Type 1 Sync. DRAM */ + +#define S3C3410X_BANKCON0 (S3C3410X_BASE+0x2000) /* Memory Bank 0 Control */ +#define S3C3410X_BANKCON1 (S3C3410X_BASE+0x2004) /* Memory Bank 1 Control */ +#define S3C3410X_BANKCON2 (S3C3410X_BASE+0x2008) /* Memory Bank 2 Control */ +#define S3C3410X_BANKCON3 (S3C3410X_BASE+0x200C) /* Memory Bank 3 Control */ +#define S3C3410X_BANKCON4 (S3C3410X_BASE+0x2010) /* Memory Bank 4 Control */ +#define S3C3410X_BANKCON5 (S3C3410X_BASE+0x2014) /* Memory Bank 5 Control */ +#define S3C3410X_BANKCON6 (S3C3410X_BASE+0x2018) /* Memory Bank 6 Control */ +#define S3C3410X_BANKCON7 (S3C3410X_BASE+0x201C) /* Memory Bank 7 Controlr */ + +#define S3C3410X_BANKCON_DBW 0x00000001 /* Data Bus Width (16Bit enable) else 8Bit */ +#define S3C3410X_BANKCON_PMC_1D 0x00000000 /* Page Mode 1Data */ +#define S3C3410X_BANKCON_PMC_4D 0x00000002 /* Page Mode 4Data */ +#define S3C3410X_BANKCON_PMC_8D 0x00000004 /* Page Mode 8Data */ +#define S3C3410X_BANKCON_PMC_16D 0x00000006 /* Page Mode 16Data */ +#define S3C3410X_BANKCON_SM 0x00000008 /* UB/LB Byte selection enable (see nWE,WE in Chipdesign) */ +#define S3C3410X_BANKCON_TACC_DIS 0x00000000 /* Access Cycle Timing Disabled */ +#define S3C3410X_BANKCON_TACC_2C 0x00000010 /* Access Cycle Timing 2Clocks */ +#define S3C3410X_BANKCON_TACC_3C 0x00000020 /* Access Cycle Timing 3Clocks */ +#define S3C3410X_BANKCON_TACC_4C 0x00000030 /* Access Cycle Timing 4Clocks */ +#define S3C3410X_BANKCON_TACC_5C 0x00000040 /* Access Cycle Timing 5Clocks */ +#define S3C3410X_BANKCON_TACC_6C 0x00000050 /* Access Cycle Timing 6Clocks */ +#define S3C3410X_BANKCON_TACC_7C 0x00000060 /* Access Cycle Timing 7Clocks */ +#define S3C3410X_BANKCON_TACC_10C 0x00000070 /* Access Cycle Timing 10Clocks */ +#define S3C3410X_BANKCON_TACP_2C 0x00000080 /* Page Mode Access Cycle Timing 2Clocks */ +#define S3C3410X_BANKCON_TACP_3C 0x00000100 /* Page Mode Access Cycle Timing 3Clocks */ +#define S3C3410X_BANKCON_TACP_4C 0x00000180 /* Page Mode Access Cycle Timing 4Clocks */ +#define S3C3410X_BANKCON_TACP_5C 0x00000000 /* Page Mode Access Cycle Timing 5Clocks */ + +#define S3C3410X_REFCON (S3C3410X_BASE+0x2020) /* DRAM Refresh Control */ + +#define S3C3410X_EXTCON0 (S3C3410X_BASE+0x2030) /* Extra device control 0 */ +#define S3C3410X_EXTCON1 (S3C3410X_BASE+0x2034) /* Extra device control 1 */ +#define S3C3410X_EXTPORT (S3C3410X_BASE+0x203E) /* External port data */ + +#define S3C3410X_EXTDAT0 (S3C3410X_BASE+0x202C) /* Extra chip selection data 0 */ +#define S3C3410X_EXTDAT1 (S3C3410X_BASE+0x202E) /* Extra chip selection data 1 */ + +/* ************* */ +/* DMA Registers */ +/* ************* */ +#define S3C3410X_DMACON0 (S3C3410X_BASE+0x300C) /* DMA 0 control */ +#define S3C3410X_DMASRC0 (S3C3410X_BASE+0x3000) /* DMA 0 source address */ +#define S3C3410X_DMADST0 (S3C3410X_BASE+0x3004) /* DMA 0 destination address */ +#define S3C3410X_DMACNT0 (S3C3410X_BASE+0x3008) /* DMA 0 transfer count */ + +#define S3C3410X_DMACON1 (S3C3410X_BASE+0x400C) /* DMA 1 control */ +#define S3C3410X_DMASRC1 (S3C3410X_BASE+0x4000) /* DMA 1 source address */ +#define S3C3410X_DMADST1 (S3C3410X_BASE+0x4004) /* DMA 1 destination address */ +#define S3C3410X_DMACNT1 (S3C3410X_BASE+0x4008) /* DMA 1 transfer count */ + +/* ******************* */ +/* I/O Ports Registers */ +/* ******************* */ +#define S3C3410X_PDAT0 (S3C3410X_BASE+0xB000) /* Port 0 data */ +#define S3C3410X_PDAT1 (S3C3410X_BASE+0xB001) /* Port 1 data */ +#define S3C3410X_PDAT2 (S3C3410X_BASE+0xB002) /* Port 2 data */ +#define S3C3410X_PDAT3 (S3C3410X_BASE+0xB003) /* Port 3 data */ +#define S3C3410X_PDAT4 (S3C3410X_BASE+0xB004) /* Port 4 data */ +#define S3C3410X_PDAT5 (S3C3410X_BASE+0xB005) /* Port 5 data */ +#define S3C3410X_PDAT6 (S3C3410X_BASE+0xB006) /* Port 6 data */ +#define S3C3410X_PDAT7 (S3C3410X_BASE+0xB007) /* Port 7 data */ +#define S3C3410X_PDAT8 (S3C3410X_BASE+0xB008) /* Port 8 data */ +#define S3C3410X_PDAT9 (S3C3410X_BASE+0xB009) /* Port 9 data */ + +#define S3C3410X_P7BR (S3C3410X_BASE+0xB00B) /* Port 7 buffer */ + +#define S3C3410X_PCON0 (S3C3410X_BASE+0xB010) /* Port 0 control */ +#define S3C3410X_PCON1 (S3C3410X_BASE+0xB012) /* Port 1 control */ +#define S3C3410X_PCON2 (S3C3410X_BASE+0xB014) /* Port 2 control */ +#define S3C3410X_PCON3 (S3C3410X_BASE+0xB016) /* Port 3 control */ +#define S3C3410X_PCON4 (S3C3410X_BASE+0xB018) /* Port 4 control */ +#define S3C3410X_PCON5 (S3C3410X_BASE+0xB01C) /* Port 5 control */ +#define S3C3410X_PCON6 (S3C3410X_BASE+0xB020) /* Port 6 control */ +#define S3C3410X_PCON7 (S3C3410X_BASE+0xB024) /* Port 7 control */ +#define S3C3410X_PCON8 (S3C3410X_BASE+0xB026) /* Port 8 control */ +#define S3C3410X_PCON9 (S3C3410X_BASE+0xB027) /* Port 9 control */ + +#define S3C3410X_PUR0 (S3C3410X_BASE+0xB028) /* Port 0 pull-up control */ +#define S3C3410X_PDR1 (S3C3410X_BASE+0xB029) /* Port 1 pull-down control */ +#define S3C3410X_PUR2 (S3C3410X_BASE+0xB02A) /* Port 2 pull-up control */ +#define S3C3410X_PUR3 (S3C3410X_BASE+0xB02B) /* Port 3 pull-up control */ +#define S3C3410X_PDR4 (S3C3410X_BASE+0xB02C) /* Port 4 pull-down control */ +#define S3C3410X_PUR5 (S3C3410X_BASE+0xB02D) /* Port 5 pull-up control */ +#define S3C3410X_PUR6 (S3C3410X_BASE+0xB02E) /* Port 6 pull-up control */ +#define S3C3410X_PUR7 (S3C3410X_BASE+0xB02F) /* Port 7 pull-up control */ +#define S3C3410X_PUR8 (S3C3410X_BASE+0xB03C) /* Port 8 pull-up control */ + +#define S3C3410X_EINTPND (S3C3410X_BASE+0xB031) /* External interrupt pending */ +#define S3C3410X_EINTCON (S3C3410X_BASE+0xB032) /* External interrupt control */ +#define S3C3410X_EINTMOD (S3C3410X_BASE+0xB034) /* External interrupt mode */ + +/* *************** */ +/* Timer Registers */ +/* *************** */ + +#define S3C3410X_TDAT0 (S3C3410X_BASE+0x9000) /* Timer 0 data */ +#define S3C3410X_TPRE0 (S3C3410X_BASE+0x9002) /* Timer 0 prescaler */ +#define S3C3410X_TCON0 (S3C3410X_BASE+0x9003) /* Timer 0 control */ +#define S3C3410X_TCNT0 (S3C3410X_BASE+0x9006) /* Timer 0 counter */ + +#define S3C3410X_T16_ICS 0x00000004 /* 16Bit-Timer Input Select */ +#define S3C3410X_T16_OMS_MODE 0x00000038 /* 16Bit-Timer Mode bits */ +#define S3C3410X_T16_OMS_INTRV 0x00000000 /* 16Bit-Timer Mode (interval mode) */ +#define S3C3410X_T16_OMS_MAOF 0x00000008 /* 16Bit-Timer Mode (match & overflow mode) */ +#define S3C3410X_T16_OMS_MAD 0x00000010 /* 16Bit-Timer Mode (match & DMA mode) */ +#define S3C3410X_T16_OMS_CAPF 0x00000020 /* 16Bit-Timer Mode (capture on falling edge of TCAP 0,1,2) */ +#define S3C3410X_T16_OMS_CAPR 0x00000028 /* 16Bit-Timer Mode (capture on rising edge of TCAP 0,1,2) */ +#define S3C3410X_T16_OMS_CAPRF 0x00000030 /* 16Bit-Timer Mode (capture on rising/falling edge of TCAP 0,1,2) */ +#define S3C3410X_T16_CL 0x00000040 /* 16Bit-Timer Clear */ +#define S3C3410X_T16_TEN 0x00000080 /* 16Bit-Timer Enable */ + +#define S3C3410X_TDAT1 (S3C3410X_BASE+0x9010) /* Timer 1 data */ +#define S3C3410X_TPRE1 (S3C3410X_BASE+0x9012) /* Timer 1 prescaler */ +#define S3C3410X_TCON1 (S3C3410X_BASE+0x9013) /* Timer 1 control */ +#define S3C3410X_TCNT1 (S3C3410X_BASE+0x9016) /* Timer 1 counter */ + +#define S3C3410X_TDAT2 (S3C3410X_BASE+0x9020) /* Timer 2 data */ +#define S3C3410X_TPRE2 (S3C3410X_BASE+0x9022) /* Timer 2 prescaler */ +#define S3C3410X_TCON2 (S3C3410X_BASE+0x9023) /* Timer 2 control */ +#define S3C3410X_TCNT2 (S3C3410X_BASE+0x9026) /* Timer 2 counter */ + +#define S3C3410X_TDAT3 (S3C3410X_BASE+0x9030) /* Timer 3 data */ +#define S3C3410X_TPRE3 (S3C3410X_BASE+0x9032) /* Timer 3 prescaler */ +#define S3C3410X_TCON3 (S3C3410X_BASE+0x9033) /* Timer 3 control */ +#define S3C3410X_TCNT3 (S3C3410X_BASE+0x9037) /* Timer 3 counter */ + +#define S3C3410X_TDAT4 (S3C3410X_BASE+0x9041) /* Timer 4 data */ +#define S3C3410X_TPRE4 (S3C3410X_BASE+0x9042) /* Timer 4 prescaler */ +#define S3C3410X_TCON4 (S3C3410X_BASE+0x9043) /* Timer 4 control */ +#define S3C3410X_TCNT4 (S3C3410X_BASE+0x9047) /* Timer 4 counter */ +#define S3C3410X_TFCON (S3C3410X_BASE+0x904F) /* Timer 4 FIFO control */ +#define S3C3410X_TFSTAT (S3C3410X_BASE+0x904E) /* Timer 4 FIFO status */ +#define S3C3410X_TFB4 (S3C3410X_BASE+0x904B) /* Timer 4 FIFO @ byte */ +#define S3C3410X_TFHW4 (S3C3410X_BASE+0x904A) /* Timer 4 FIFO @ half-word */ +#define S3C3410X_TFW4 (S3C3410X_BASE+0x9048) /* Timer 4 FIFO @ word */ + +/* #define TDATA0 TDAT0 + #define TMOD TCON0 */ + +/* ************** */ +/* UART Registers */ +/* ************** */ + +#define S3C3410X_UART_BASE (S3C3410X_BASE) /* "virtual" start of UART registers */ + +#define S3C3410X_ULCON (0x5003) /* UART line control */ +#define S3C3410X_UCON (0x5007) /* UART control */ +#define S3C3410X_USTAT (0x500B) /* UART status */ +#define S3C3410X_UFCON (0x500F) /* UART FIFO control */ +#define S3C3410X_UFSTAT (0x5012) /* UART FIFO status */ +#define S3C3410X_UTXH (0x5017) /* UART transmit holding */ +#define S3C3410X_UTXH_B (0x5017) /* UART transmit FIFO @ byte */ +#define S3C3410X_UTXH_HW (0x5016) /* UART transmit FIFO @ half-word */ +#define S3C3410X_UTXH_W (0x5014) /* UART transmit FIFO @ word */ +#define S3C3410X_URXH (0x501B) /* UART receive holding */ +#define S3C3410X_URXH_B (0x501B) /* UART receive FIFO @ byte */ +#define S3C3410X_URXH_HW (0x501A) /* UART receive FIFO @ half-word */ +#define S3C3410X_URXH_W (0x5018) /* UART receive FIFO @ word */ +#define S3C3410X_UBRDIV (0x501E) /* baud rate divisor */ + +/* UART Line Control Register Bits */ +#define ULCON_WL_MASK 0x03 /* UART Word Length Mask */ +#define ULCON_WL_5 0x00 /* UART Word Length: 5 bits */ +#define ULCON_WL_6 0x01 /* UART Word Length: 6 bits */ +#define ULCON_WL_7 0x02 /* UART Word Length: 7 bits */ +#define ULCON_WL_8 0x03 /* UART Word Length: 8 bits */ +#define ULCON_SB 0x04 /* UART Stop Bits */ +#define ULCON_PMD_MASK 0x38 /* UART Parity Mode Mask */ +#define ULCON_PMD_NONE 0x00 /* UART Parity Mode: None */ +#define ULCON_PMD_ODD 0x20 /* UART Parity Mode: Odd */ +#define ULCON_PMD_EVEN 0x28 /* UART Parity Mode: Even */ +#define ULCON_IRM 0x40 /* UART Infrared Mode */ +/* 0x80 unused */ + + +/* UART Control Register Bits */ +#define UCON_RM_MASK 0x03 /* UART Mask for Receive Mode */ +#define UCON_RM_DISABLED 0x00 /* UART Receive Mode 0 : Disabled */ +#define UCON_RM_IRQ_POLL 0x01 /* UART Receive Mode 1 : Interrupt or Polling Mode */ +#define UCON_RM_DMA0 0x02 /* UART Receive Mode 2 : DMA0 request */ +#define UCON_RM_DMA1 0x03 /* UART Receive Mode 3 : DMA1 request */ + +#define UCON_TM_MASK 0x0C /* UART Mask for Transmit Mode */ +#define UCON_TM_DISABLED 0x00 /* UART Transmit Mode 0 : Disabled */ +#define UCON_TM_IRQ_POLL 0x04 /* UART Transmit Mode 1 : Interrupt or Polling Mode */ +#define UCON_TM_DMA0 0x08 /* UART Transmit Mode 2 : DMA0 request */ +#define UCON_TM_DMA1 0x0C /* UART Transmit Mode 3 : DMA1 request */ + +#define UCON_SBS 0x10 /* UART Send Break Signal */ +#define UCON_LBM 0x20 /* UART Loopback Mode */ +#define UCON_RSIE 0x40 /* UART Rx Status Interrupt Enable */ +#define UCON_RXTOEL 0x80 /* UART Rx Timeout Enable */ + +/* UART Status Register Bits */ +#define USTAT_OE 0x01 /* UART Overrun Error */ +#define USTAT_PE 0x02 /* UART Parity Error */ +#define USTAT_FE 0x04 /* UART Framing Error */ +#define USTAT_BD 0x08 /* UART Break Detect */ +#define USTAT_RTO 0x10 /* UART Receiver Time Out */ +#define USTAT_RFDR 0x20 /* UART Receive FIFO Data Ready / Rx Buffer Data Ready */ +#define USTAT_TFE 0x40 /* UART Transmit FIFO Empty / Tx Holding Register Empty */ +#define USTAT_TSE 0x80 /* UART Transmit Shift Register Empty */ + +/* UART FIFO Control Register Bits */ +#define UFCON_FE 0x01 /* UART FIFO Enable */ +#define UFCON_RFR 0x02 /* UART Rx FIFO Reset */ +#define UFCON_TFR 0x04 /* UART Tx FIFO Reset */ +/* 0x08 reserved */ +#define UFCON_RFTL_MASK 0x30 /* UART Receive FIFO Trigger Level Mask */ +#define UFCON_RFTL_2 0x00 /* UART Receive FIFO Trigger Level: 2 byte */ +#define UFCON_RFTL_4 0x10 /* UART Receive FIFO Trigger Level: 4 byte */ +#define UFCON_RFTL_6 0x20 /* UART Receive FIFO Trigger Level: 6 byte */ +#define UFCON_RFTL_8 0x30 /* UART Receive FIFO Trigger Level: 8 byte */ + +#define UFCON_TFTL_MASK 0x30 /* UART Transmit FIFO Trigger Level Mask */ +#define UFCON_TFTL_0 0x00 /* UART Transmit FIFO Trigger Level: 0 byte */ +#define UFCON_TFTL_2 0x10 /* UART Transmit FIFO Trigger Level: 2 byte */ +#define UFCON_TFTL_4 0x20 /* UART Transmit FIFO Trigger Level: 4 byte */ +#define UFCON_TFTL_6 0x30 /* UART Transmit FIFO Trigger Level: 6 byte */ + +#define UFSTAT_RFC_MASK 0x07 /* UART FIFO STATUS Rx FIFO count */ +#define UFSTAT_TFC_MASK 0x38 /* UART FIFO STATUS Rx FIFO count */ +#define UFSTAT_RFF 0x20 /* UART FIFO STATUS Receive FIFO FULL */ +#define UFSTAT_TFF 0x40 /* UART FIFO STATUS Transmit FIFO FULL */ +#define UFSTAT_EIF 0x80 /* UART FIFO STATUS Error in FIFO */ + + +/* *********** */ +/* SIO 0 and 1 */ +/* *********** */ + +#define S3C3410X_ITVCNT0 (S3C3410X_BASE+0x6000) /* SIO 0 interval counter */ +#define S3C3410X_SBRDR0 (S3C3410X_BASE+0x6001) /* SIO 0 baud rate prescaler */ +#define S3C3410X_SIODAT0 (S3C3410X_BASE+0x6002) /* SIO 0 data */ +#define S3C3410X_SIOCON0 (S3C3410X_BASE+0x6003) /* SIO 0 control */ + +#define S3C3410X_ITVCNT1 (S3C3410X_BASE+0x7000) /* SIO 1 interval counter */ +#define S3C3410X_SBRDR1 (S3C3410X_BASE+0x7001) /* SIO 1 baud rate prescaler */ +#define S3C3410X_SIODAT1 (S3C3410X_BASE+0x7002) /* SIO 1 data */ +#define S3C3410X_SIOCON1 (S3C3410X_BASE+0x7003) /* SIO 1 control */ + +/* ****************************** */ +/* Interrupt Controller Registers */ +/* ****************************** */ + +#define S3C3410X_INTMOD (S3C3410X_BASE+0xC000) /* Interrupt mode */ +#define S3C3410X_INTPND (S3C3410X_BASE+0xC004) /* Interrupt pending */ +#define S3C3410X_INTMSK (S3C3410X_BASE+0xC008) /* Interrupt mask */ + +#define S3C3410X_INTPRI0 (S3C3410X_BASE+0xC00C) /* Interrupt priority 0 */ +#define S3C3410X_INTPRI1 (S3C3410X_BASE+0xC010) /* Interrupt priority 1 */ +#define S3C3410X_INTPRI2 (S3C3410X_BASE+0xC014) /* Interrupt priority 2 */ +#define S3C3410X_INTPRI3 (S3C3410X_BASE+0xC018) /* Interrupt priority 3 */ +#define S3C3410X_INTPRI4 (S3C3410X_BASE+0xC01C) /* Interrupt priority 4 */ +#define S3C3410X_INTPRI5 (S3C3410X_BASE+0xC020) /* Interrupt priority 5 */ +#define S3C3410X_INTPRI6 (S3C3410X_BASE+0xC024) /* Interrupt priority 6 */ +#define S3C3410X_INTPRI7 (S3C3410X_BASE+0xC028) /* Interrupt priority 7 */ + +/* *** */ +/* ADC */ +/* *** */ + +#define S3C3410X_ADCCON (S3C3410X_BASE+0x8002) /* A/D Converter control */ +#define S3C3410X_ADCDAT (S3C3410X_BASE+0x8006) /* A/D Converter data */ + +/* *********** */ +/* Basic Timer */ +/* *********** */ + +#define S3C3410X_BTCON (S3C3410X_BASE+0xA002) /* Basic Timer control */ +#define S3C3410X_BTCON_WDTC 0x00000001 /* Watchdog Timer Clear */ +#define S3C3410X_BTCON_BTC 0x00000002 /* Basic Timer Clear */ +#define S3C3410X_BTCON_CS_13 0x00000000 /* Watchdog Clock source Fin / 2^13 */ +#define S3C3410X_BTCON_CS_12 0x00000040 /* Watchdog Clock source Fin / 2^12 */ +#define S3C3410X_BTCON_CS_11 0x00000080 /* Watchdog Clock source Fin / 2^11 */ +#define S3C3410X_BTCON_CS_9 0x000000C0 /* Watchdog Clock source Fin / 2^9 */ + +/* When this value is written into BTCON it will disable the Timer. Any other value will enable it. */ +#define S3C3410X_BTCON_WDTD 0x0000A500 /* Watchdog Timer Disable */ +#define S3C3410X_BTCON_WDTE 0x0000FF00 /* Watchdog Timer Enable */ + +#define S3C3410X_BTCNT (S3C3410X_BASE+0xA007) /* Basic Timer count */ + +/* ***************** */ +/* I2C Bus Registers */ +/* ***************** */ + +#define S3C3410X_IICCON (S3C3410X_BASE+0xE000) /* IIC-bus control */ +#define S3C3410X_IICSTAT (S3C3410X_BASE+0xE001) /* IIC-bus status */ +#define S3C3410X_IICDS (S3C3410X_BASE+0xE002) /* IIC-bus tx/rx data shift reg. */ +#define S3C3410X_IICADD (S3C3410X_BASE+0xE003) /* IIC-bus tx/rx address */ +#define S3C3410X_IICPC (S3C3410X_BASE+0xE004) /* IIC-bus Prescaler */ +#define S3C3410X_IICPCNT (S3C3410X_BASE+0xE005) /* IIC-bus Prescaler counter */ + +/* *********************** */ +/* System control register */ +/* *********************** */ + +#define S3C3410X_SYSCON (S3C3410X_BASE+0xD003) /* System control */ + +#define S3C3410X_SYSCON_STOP 0x00000001 /* STOP-Mode */ +#define S3C3410X_SYSCON_IDLE 0x00000002 /* IDLE-Mode */ +#define S3C3410X_SYSCON_DMAIDLE 0x00000004 /* DMA-IDLE-Mode */ +#define S3C3410X_SYSCON_MCLK16 0x00000000 /* system clock = MCLOCK / 16 */ +#define S3C3410X_SYSCON_MCLK2 0x00000010 /* system clock = MCLOCK / 2 */ +#define S3C3410X_SYSCON_MCLK1024 0x00000020 /* system clock = MCLOCK / 1024 */ +#define S3C3410X_SYSCON_MCLK8 0x00000008 /* system clock = MCLOCK / 8 */ +#define S3C3410X_SYSCON_MCLK 0x00000018 /* system clock = MCLOCK */ +#define S3C3410X_SYSCON_GIE 0x00000040 /* Global Interrupt Enable (set when enabled !!) */ + +/* ************** */ +/* Realtime Clock */ +/* ************** */ + +#define S3C3410X_RTCCON (S3C3410X_BASE+0xA013) /* RTC control */ +#define S3C3410X_RTCALM (S3C3410X_BASE+0xA012) /* RTC alarm control */ +#define S3C3410X_ALMSEC (S3C3410X_BASE+0xA033) /* Alarm second */ +#define S3C3410X_ALMMIN (S3C3410X_BASE+0xA032) /* Alarm minute */ +#define S3C3410X_ALMHOUR (S3C3410X_BASE+0xA031) /* Alarm hour */ +#define S3C3410X_ALMDAY (S3C3410X_BASE+0xA037) /* Alarm day */ +#define S3C3410X_ALMMON (S3C3410X_BASE+0xA036) /* Alarm month */ +#define S3C3410X_ALMYEAR (S3C3410X_BASE+0xA035) /* Alarm year */ +#define S3C3410X_BCDSEC (S3C3410X_BASE+0xA023) /* BCD second */ +#define S3C3410X_BCDMIN (S3C3410X_BASE+0xA022) /* BCD minute */ +#define S3C3410X_BCDHOUR (S3C3410X_BASE+0xA021) /* BCD hour */ +#define S3C3410X_BCDDAY (S3C3410X_BASE+0xA027) /* BCD day */ +#define S3C3410X_BCDDATE (S3C3410X_BASE+0xA020) /* BCD date */ +#define S3C3410X_BCDMON (S3C3410X_BASE+0xA026) /* BCD month */ +#define S3C3410X_BCDYEAR (S3C3410X_BASE+0xA025) /* BCD year */ + +#define S3C3410X_RINTPND (S3C3410X_BASE+0xA010) /* RTC time interrupt pending */ +#define S3C3410X_RINTCON (S3C3410X_BASE+0xA011) /* RTC time interrupt control */ + +#endif /* __ASM_ARCH_S3C3410_H */ diff --git a/include/asm-arm/arch-s3c3410/system.h b/include/asm-arm/arch-s3c3410/system.h new file mode 100644 index 00000000..30e807bb --- /dev/null +++ b/include/asm-arm/arch-s3c3410/system.h @@ -0,0 +1,29 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/system.h + * + * Copyright (C) 2002 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0); +} + +#endif diff --git a/include/asm-arm/arch-s3c3410/time.h b/include/asm-arm/arch-s3c3410/time.h new file mode 100644 index 00000000..d47ce937 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/time.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-s3c3410/time.h + * + * 2003 Thomas Eschenbacher + * modifed by Hyok S. Choi + * + * Setup for 16 bit timer 0, used as system timer. + * + */ + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ + +#include +#include +#include +#include + +#define CLOCKS_PER_USEC (CONFIG_ARM_CLK/1000000) + +#define S3C3410X_TIMER0_PRESCALER 100 + +#endif diff --git a/include/asm-arm/arch-s3c3410/timex.h b/include/asm-arm/arch-s3c3410/timex.h new file mode 100644 index 00000000..34685e47 --- /dev/null +++ b/include/asm-arm/arch-s3c3410/timex.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/timex.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ + +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE (CONFIG_ARM_CLK) + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-s3c3410/vmalloc.h b/include/asm-arm/arch-s3c3410/vmalloc.h new file mode 100644 index 00000000..86204bee --- /dev/null +++ b/include/asm-arm/arch-s3c3410/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/vmalloc.h + * + * Copyright (C) 2000 Russell King. + * modified by Hyok S. Choi + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_S3C3410_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_S3C3410_SDRAM_SIZE) diff --git a/include/asm-arm/arch-s3c44b0x/dma.h b/include/asm-arm/arch-s3c44b0x/dma.h new file mode 100644 index 00000000..ed733dda --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/dma.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-armnommu/arch-s3c44b0x/dma.h + */ + +#include +#include + +#ifndef __ASM_S3C44B0X_ARCH_DMA_H +#define __ASM_S3C44B0X_ARCH_DMA_H + +// TODO: include dma support + +#define MAX_DMA_ADDRESS 0x0D000000 + +#define MAX_DMA_CHANNELS 0 +#define MAX_DMA_TRANSFER_SIZE 0x100000 + +#endif /* _ASM_S3C44B0X_ARCH_DMA_H */ + diff --git a/include/asm-arm/arch-s3c44b0x/entry-macro.S b/include/asm-arm/arch-s3c44b0x/entry-macro.S new file mode 100644 index 00000000..67bdec30 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/entry-macro.S @@ -0,0 +1,31 @@ +/* + * arch/armnommu/mach-s3c44b0x/entry-macro.S + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + */ + +#ifndef CONFIG_ARCH_S3C44B0 +#error +#endif + .macro disable_fiq + /* FIXME */ + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =S3C44B0X_I_ISPR + ldr \base, [\base] + mov \irqnr, #0 +2222: + tst \base, #1 + bne 1111f + add \irqnr, \irqnr, #1 + mov \base, \base, lsr #1 + cmp \irqnr, #NR_IRQS + bcc 2222b +1111: + .endm + + .macro irq_prio_table + /* FIXME */ + .endm diff --git a/include/asm-arm/arch-s3c44b0x/hardware.h b/include/asm-arm/arch-s3c44b0x/hardware.h new file mode 100644 index 00000000..53aaa8fb --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/hardware.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-arm/arch-s3c44b0x/hardware.h + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#ifndef __ASSEMBLY__ + +#define HARD_RESET_NOW() + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (1) + +#endif + +#define MEM_SIZE CONFIG_DRAM_SIZE +#define PA_SDRAM_BASE CONFIG_DRAM_BASE + +/* The default system speed this box runs */ +#if !defined(CONFIG_ARM_CLK) +#define CONFIG_ARM_CLK 60000000 +#endif + +#if !defined(CONFIG_ARM_CLK_FIN) +#define CONFIG_ARM_CLK_FIN 8000000 +#endif + +#endif /* END OF __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-s3c44b0x/io.h b/include/asm-arm/arch-s3c44b0x/io.h new file mode 100644 index 00000000..7142768e --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/io.h @@ -0,0 +1,63 @@ +/* + * linux/include/asm-arm/arch-s3c3410/io.h + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + /* Used in kernel/resource.c */ + +/* + * We have the this routine to use usb host device driver + */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + + +/* + * These macros were copied from arch/armnommu/io.h and are used instead + * of the definitions found there, because we want to do 16/32 bit i/o + * without byte swapping. + * --the + */ + +#undef __io + +#ifndef __iob + #define __iob(a) __io(a) +#endif + +#define outb(v,p) __raw_writeb(v, p) +#define outw(v,p) __raw_writew(v, p) +#define outl(v,p) __raw_writel(v, p) + +#define inb(p) ({ unsigned int __v = __raw_readb(p); __v; }) +#define inw(p) ({ unsigned int __v = __raw_readw(p); __v; }) +#define inl(p) ({ unsigned int __v = __raw_readl(p); __v; }) + +#define outsb(p,d,l) __raw_writesb(p, d, l) +#define outsw(p,d,l) __raw_writesw(p, d, l) +#define outsl(p,d,l) __raw_writesl(p, d, l) + +#define insb(p,d,l) __raw_readsb(p, d, l) +#define insw(p,d,l) __raw_readsw(p, d, l) +#define insl(p,d,l) __raw_readsl(p, d, l) + +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) (1) + + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-s3c44b0x/irq.h b/include/asm-arm/arch-s3c44b0x/irq.h new file mode 100644 index 00000000..ec0116b6 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/irq.h @@ -0,0 +1,20 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/irq.h + */ +#ifndef __S3C3410_irq_h +#define __S3C3410_irq_h + +#include +#include +#include +#include + +extern unsigned int fixup_irq(int i); + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void s3c3410_init_irq(void); + +#define irq_init_irq s3c3410_init_irq + +#endif diff --git a/include/asm-arm/arch-s3c44b0x/irqs.h b/include/asm-arm/arch-s3c44b0x/irqs.h new file mode 100644 index 00000000..67e8448d --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/irqs.h @@ -0,0 +1,37 @@ +/* + * linux/include/asm-armnommu/arch-s3c44b0x/irqs.h + */ + +#ifndef _S3C44B0X_IRQS_H +#define _S3C44B0X_IRQS_H 1 + +#define NR_IRQS 26 + +#define S3C44B0X_INTERRUPT_EINT0 25 /* External int. 0 */ +#define S3C44B0X_INTERRUPT_EINT1 24 /* External int. 1 */ +#define S3C44B0X_INTERRUPT_EINT2 23 /* External int. 2 */ +#define S3C44B0X_INTERRUPT_EINT3 22 /* External int. 3 */ +#define S3C44B0X_INTERRUPT_EINT4567 21 /* External int. 4,5,6 and 7 */ +#define S3C44B0X_INTERRUPT_TICK 20 /* Clock Tick int. */ +#define S3C44B0X_INTERRUPT_ZDMA0 19 /* ZDMA 0 */ +#define S3C44B0X_INTERRUPT_ZDMA1 18 /* ZDMA 1 */ +#define S3C44B0X_INTERRUPT_BDMA0 17 /* BDMA 0 */ +#define S3C44B0X_INTERRUPT_BDMA1 16 /* BDMA 1 */ +#define S3C44B0X_INTERRUPT_WDT 15 /* Watchdog timer */ +#define S3C44B0X_INTERRUPT_UERR 14 /* UART error */ +#define S3C44B0X_INTERRUPT_TIMER0 13 /* Timer 0 zero-crossing */ +#define S3C44B0X_INTERRUPT_TIMER1 12 /* Timer 1 zero-crossing */ +#define S3C44B0X_INTERRUPT_TIMER2 11 /* Timer 2 zero-crossing */ +#define S3C44B0X_INTERRUPT_TIMER3 10 /* Timer 3 zero-crossing */ +#define S3C44B0X_INTERRUPT_TIMER4 9 /* Timer 4 zero-crossing */ +#define S3C44B0X_INTERRUPT_TIMER5 8 /* Timer 5 zero-crossing */ +#define S3C44B0X_INTERRUPT_URX0 7 /* UART0 receive */ +#define S3C44B0X_INTERRUPT_URX1 6 /* UART1 receive */ +#define S3C44B0X_INTERRUPT_IIC 5 /* IIC */ +#define S3C44B0X_INTERRUPT_SIO 4 /* SIO */ +#define S3C44B0X_INTERRUPT_UTX0 3 /* UART0 transmit */ +#define S3C44B0X_INTERRUPT_UTX1 2 /* UART1 transmit */ +#define S3C44B0X_INTERRUPT_RTCT 1 /* RTC time */ +#define S3C44B0X_INTERRUPT_ADC 0 /* ADC interrupt */ + +#endif /* End of _S3C44B0X_IRQS_H */ diff --git a/include/asm-arm/arch-s3c44b0x/keyboard.h b/include/asm-arm/arch-s3c44b0x/keyboard.h new file mode 100644 index 00000000..650966d2 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/keyboard.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/keyboard.h + */ +#ifndef __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H +#define __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) +#define kbd_translate(sc,kcp,rm) ({ *(kcp) = (sc); 1; }) +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) +#define kbd_init_hw() +#define kbd_enable_irq() +#define kbd_disable_irq() + +#endif /* __ASM_ARMNOMMU_ARCH_S3C3410_KEYBOARD_H */ diff --git a/include/asm-arm/arch-s3c44b0x/memory.h b/include/asm-arm/arch-s3c44b0x/memory.h new file mode 100644 index 00000000..188b28f4 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/memory.h @@ -0,0 +1,22 @@ +/* + * linux/include/asm-arm/arch-s3c3410/memory.h + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x0cc00000UL) +#define TASK_SIZE_26 TASK_SIZE + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + + + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((void *) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((void *) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-s3c44b0x/param.h b/include/asm-arm/arch-s3c44b0x/param.h new file mode 100644 index 00000000..8a1d92b2 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/param.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-s3c44b0x/s3c44b0x.h b/include/asm-arm/arch-s3c44b0x/s3c44b0x.h new file mode 100644 index 00000000..85acb3f3 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/s3c44b0x.h @@ -0,0 +1,704 @@ +#ifndef _S3C44B0X_H_ +#define _S3C44B0X_H_ + +#ifndef __ASSEMBLY__ +#include +#include + +/* macros defined to easy the operation of system registers */ +#define SYSREG_GET(r) inl(r) +#define SYSREG_SET(r, v) outl((v), r) +#define SYSREG_AND_SET(r, v) outl(SYSREG_GET(r) & (v), r) +#define SYSREG_OR_SET(r, v) outl(SYSREG_GET(r) | (v), r) +#define SYSREG_CLR(r, v) SYSREG_AND_SET(r, ~(v)) + +#define SYSREG_GETB(r) inb(r) +#define SYSREG_SETB(r, v) outb((v), r) +#define SYSREG_AND_SETB(r, v) outb(SYSREG_GETB(r) & (v), r) +#define SYSREG_OR_SETB(r, v) outb(SYSREG_GETB(r) | (v), r) +#define SYSREG_CLRB(r, v) SYSREG_AND_SETB(r, ~(v)) + +#define SYSREG_GETW(r) inw(r) +#define SYSREG_SETW(r, v) outw((v), r) +#define SYSREG_AND_SETW(r, v) outw(SYSREG_GETW(r) & (v), r) +#define SYSREG_OR_SETW(r, v) outw(SYSREG_GETW(r) | (v), r) +#define SYSREG_CLRW(r, v) SYSREG_AND_SETW(r, ~(v)) + +#endif + +/** + * register definitions for SAMSUNG S3C44B0X + * + * Copyright (C) 2003 Christian Schulte + * + */ + +/*******************/ +/*** CPU WRAPPER ***/ +/*******************/ + +#define S3C44B0X_SYSCFG 0x01c00000 +#define S3C44B0X_NCACHBE0 0x01c00004 /* configuration of non-cachable areas */ +#define S3C44B0X_NCACHBE1 0x01c00008 /* configuration of non-cachable areas */ +#define S3C44B0X_SBUSCON 0x01c40000 /* bus configuration */ + +/* SYSCFG */ +#define S3C44B0X_SYSCFG_DA 0x00000020 /* Data Abort disable */ +#define S3C44B0X_SYSCFG_RSE 0x00000010 /* Read Stall Option enable */ +#define S3C44B0X_SYSCFG_WE 0x00000008 /* Write Buffer enable */ + +#define S3C44B0X_SYSCFG_CM_NONE 0x00000000 /* Cache Mode */ +#define S3C44B0X_SYSCFG_CM_4K 0x00000002 +#define S3C44B0X_SYSCFG_CM_8K 0x00000006 + +#define S3C44B0X_SYSCFG_SE 0x00000001 /* Stall Option enable */ + +/* SBUSCON */ +#define S3C44B0X_SBUSCON_FIX 0x80000000 /* use the fixed configuration that follows (instead of round-robin) */ +#define S3C44B0X_SBUSCON_S_LCD_DMA_1 0x00000000 /* read the bus priority of LCD-DMA */ +#define S3C44B0X_SBUSCON_S_LCD_DMA_2 0x00004000 +#define S3C44B0X_SBUSCON_S_LCD_DMA_3 0x00008000 +#define S3C44B0X_SBUSCON_S_LCD_DMA_4 0x0000c000 +#define S3C44B0X_SBUSCON_S_ZDMA_1 0x00000000 /* read the bus priority of Z DMA */ +#define S3C44B0X_SBUSCON_S_ZDMA_2 0x00001000 +#define S3C44B0X_SBUSCON_S_ZDMA_3 0x00002000 +#define S3C44B0X_SBUSCON_S_ZDMA_4 0x00003000 +#define S3C44B0X_SBUSCON_S_BDMA_1 0x00000000 /* read the bus priority of B DMA */ +#define S3C44B0X_SBUSCON_S_BDMA_2 0x00000400 +#define S3C44B0X_SBUSCON_S_BDMA_3 0x00000800 +#define S3C44B0X_SBUSCON_S_BDMA_4 0x00000c00 +#define S3C44B0X_SBUSCON_S_BREQ_1 0x00000000 /* read the bus priority of external BREAK REQUEST */ +#define S3C44B0X_SBUSCON_S_BREQ_2 0x00000100 +#define S3C44B0X_SBUSCON_S_BREQ_3 0x00000200 +#define S3C44B0X_SBUSCON_S_BREQ_4 0x00000300 + +#define S3C44B0X_SBUSCON_LCD_DMA_1 0x00000000 /* set the bus priority of LCD-DMA */ +#define S3C44B0X_SBUSCON_LCD_DMA_2 0x00000040 +#define S3C44B0X_SBUSCON_LCD_DMA_3 0x00000080 +#define S3C44B0X_SBUSCON_LCD_DMA_4 0x000000c0 +#define S3C44B0X_SBUSCON_ZDMA_1 0x00000000 /* set the bus priority of Z DMA */ +#define S3C44B0X_SBUSCON_ZDMA_2 0x00000010 +#define S3C44B0X_SBUSCON_ZDMA_3 0x00000020 +#define S3C44B0X_SBUSCON_ZDMA_4 0x00000030 +#define S3C44B0X_SBUSCON_BDMA_1 0x00000000 /* set the bus priority of B DMA */ +#define S3C44B0X_SBUSCON_BDMA_2 0x00000004 +#define S3C44B0X_SBUSCON_BDMA_3 0x00000008 +#define S3C44B0X_SBUSCON_BDMA_4 0x0000000c +#define S3C44B0X_SBUSCON_BREQ_1 0x00000000 /* set the bus priority of external BREAK REQUEST */ +#define S3C44B0X_SBUSCON_BREQ_2 0x00000001 +#define S3C44B0X_SBUSCON_BREQ_3 0x00000002 +#define S3C44B0X_SBUSCON_BREQ_4 0x00000003 + + /*************************/ + /*** MEMORY CONTROLLER ***/ + /*************************/ + +#define S3C44B0X_BWSCON 0x01c80000 /* Bank size, width and type of memory */ +#define S3C44B0X_BANKCON0 0x01c80004 /* timing and page modes */ +#define S3C44B0X_BANKCON1 0x01c80008 +#define S3C44B0X_BANKCON2 0x01c8000c +#define S3C44B0X_BANKCON3 0x01c80010 +#define S3C44B0X_BANKCON4 0x01c80014 +#define S3C44B0X_BANKCON5 0x01c80018 +#define S3C44B0X_BANKCON6 0x01c8001c +#define S3C44B0X_BANKCON7 0x01c80020 +#define S3C44B0X_REFRESH 0x01c80024 /* refresh timing */ +#define S3C44B0X_BANKSIZE 0x01c80028 /* bank sizes 2,4,8,16,32 MB */ +#define S3C44B0X_MRSRB6 0x01c8002c /* burst settings, CAS latency */ +#define S3C44B0X_MRSRB7 0x01c80030 + +/* BWSCON */ +#define S3C44B0X_BWSCON_ST7 0x80000000 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS7 0x40000000 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW7_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW7_16 0x10000000 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW7_32 0x20000000 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST6 0x08000000 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS6 0x04000000 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW6_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW6_16 0x01000000 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW6_32 0x02000000 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST5 0x00800000 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS5 0x00400000 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW5_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW5_16 0x00100000 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW5_32 0x00200000 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST4 0x00080000 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS4 0x00040000 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW4_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW4_16 0x00010000 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW4_32 0x00020000 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST3 0x00008000 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS3 0x00004000 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW3_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW3_16 0x00001000 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW3_32 0x00002000 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST2 0x00000800 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS2 0x00000400 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW2_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW2_16 0x00000100 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW2_32 0x00000200 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ST1 0x00000080 /* use UB/LB addressing */ +#define S3C44B0X_BWSCON_WS1 0x00000040 /* waitstate enable */ +#define S3C44B0X_BWSCON_DW1_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW1_16 0x00000010 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW1_32 0x00000020 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_DW0_8 0x00000000 /* data bus width 8bit */ +#define S3C44B0X_BWSCON_DW0_16 0x00000002 /* data bus width 16bit */ +#define S3C44B0X_BWSCON_DW0_32 0x00000004 /* data bus width 32bit */ + +#define S3C44B0X_BWSCON_ENDIAN_BIG 0x00000001 /* read-only, samples the endianess input pin */ + +/* BANKCON */ +#define S3C44B0X_BANKCON_TACS_0 0x00000000 /* time, adress setup to CS (in clocks) */ +#define S3C44B0X_BANKCON_TACS_1 0x00002000 +#define S3C44B0X_BANKCON_TACS_2 0x00004000 +#define S3C44B0X_BANKCON_TACS_4 0x00006000 + +#define S3C44B0X_BANKCON_TCOS_0 0x00000000 /* time, CS to nOE (in clocks) */ +#define S3C44B0X_BANKCON_TCOS_1 0x00000800 +#define S3C44B0X_BANKCON_TCOS_2 0x00001000 +#define S3C44B0X_BANKCON_TCOS_4 0x00001800 + +#define S3C44B0X_BANKCON_TACC_1 0x00000000 /* access cycle in clocks (in clocks) */ +#define S3C44B0X_BANKCON_TACC_2 0x00000100 +#define S3C44B0X_BANKCON_TACC_3 0x00000200 +#define S3C44B0X_BANKCON_TACC_4 0x00000300 +#define S3C44B0X_BANKCON_TACC_6 0x00000400 +#define S3C44B0X_BANKCON_TACC_8 0x00000500 +#define S3C44B0X_BANKCON_TACC_10 0x00000600 +#define S3C44B0X_BANKCON_TACC_14 0x00000700 + +#define S3C44B0X_BANKCON_TOCH_0 0x00000000 /* time, CS hold on nOE (in clocks) */ +#define S3C44B0X_BANKCON_TOCH_1 0x00000040 +#define S3C44B0X_BANKCON_TOCH_2 0x00000080 +#define S3C44B0X_BANKCON_TOCH_4 0x000000c0 + +#define S3C44B0X_BANKCON_TCAH_0 0x00000000 /* address hold on after CS (in clocks) */ +#define S3C44B0X_BANKCON_TCAH_1 0x00000010 +#define S3C44B0X_BANKCON_TCAH_2 0x00000020 +#define S3C44B0X_BANKCON_TCAH_4 0x00000030 + +#define S3C44B0X_BANKCON_TPAC_2 0x00000000 /* page mode access cycle (in clocks) */ +#define S3C44B0X_BANKCON_TPAC_3 0x00000004 +#define S3C44B0X_BANKCON_TPAC_4 0x00000008 +#define S3C44B0X_BANKCON_TPAC_6 0x0000000c + +#define S3C44B0X_BANKCON_PMC_1 0x00000000 /* page mode config (in datawords) */ +#define S3C44B0X_BANKCON_PMC_4 0x00000001 +#define S3C44B0X_BANKCON_PMC_8 0x00000002 +#define S3C44B0X_BANKCON_PMC_16 0x00000003 + +#define S3C44B0X_BANKCON_MT_SRAM 0x00000000 /* memory type selection */ +#define S3C44B0X_BANKCON_MT_DRAM 0x00004000 +#define S3C44B0X_BANKCON_MT_EDO 0x00008000 +#define S3C44B0X_BANKCON_MT_SDRAM 0x00018000 + +/* only for FP-DRAM or EDO-DRAM */ +#define S3C44B0X_BANKCON_TRCD_1 0x00000000 /* RAS to CAS delay */ +#define S3C44B0X_BANKCON_TRCD_2 0x00000010 +#define S3C44B0X_BANKCON_TRCD_3 0x00000020 +#define S3C44B0X_BANKCON_TRCD_4 0x00000030 + +#define S3C44B0X_BANKCON_TCAS_1 0x00000000 /* CAS pulse width (in clocks) */ +#define S3C44B0X_BANKCON_TCAS_2 0x00000008 + +#define S3C44B0X_BANKCON_TCP_1 0x00000000 /* CAS precharge (in clocks) */ +#define S3C44B0X_BANKCON_TCP_2 0x00000004 + +#define S3C44B0X_BANKCON_CAN_8 0x00000000 /* column address number (in bits) */ +#define S3C44B0X_BANKCON_CAN_9 0x00000001 +#define S3C44B0X_BANKCON_CAN_10 0x00000002 +#define S3C44B0X_BANKCON_CAN_11 0x00000003 + +/* only for SDRAM */ +#define S3C44B0X_BANKCON_SDRAM_TRCD_2 0x00000000 /* RAS to CAS delay */ +#define S3C44B0X_BANKCON_SDRAM_TRCD_3 0x00000004 +#define S3C44B0X_BANKCON_SDRAM_TRCD_4 0x00000008 + +#define S3C44B0X_BANKCON_SCAN_8 0x00000000 /* column address number (in bits) */ +#define S3C44B0X_BANKCON_SCAN_9 0x00000001 +#define S3C44B0X_BANKCON_SCAN_10 0x00000002 + + +/* REFRESH */ +#define S3C44B0X_REFRESH_REFEN 0x00800000 +#define S3C44B0X_REFRESH_TREFMD 0x00400000 + + +#define S3C44B0X_REFRESH_TRP_1_5 0x00000000 /* for DRAM */ +#define S3C44B0X_REFRESH_TRP_2_5 0x00000000 +#define S3C44B0X_REFRESH_TRP_3_5 0x00000000 +#define S3C44B0X_REFRESH_TRP_4_5 0x00000000 +#define S3C44B0X_REFRESH_TRP_2 0x00000000 /* for SDRAM */ +#define S3C44B0X_REFRESH_TRP_3 0x00000000 +#define S3C44B0X_REFRESH_TRP_4 0x00000000 +#define S3C44B0X_REFRESH_TRP_NONE 0x00000000 + +#define S3C44B0X_REFRESH_TRC_4 0x00000000 /* SDRAM RC minimum time */ +#define S3C44B0X_REFRESH_TRC_5 0x00040000 +#define S3C44B0X_REFRESH_TRC_6 0x00080000 +#define S3C44B0X_REFRESH_TRC_7 0x000c0000 + +#define S3C44B0X_REFRESH_TCHR_1 0x00000000 /* CAS Hold Time (DRAM) */ +#define S3C44B0X_REFRESH_TCHR_2 0x00010000 +#define S3C44B0X_REFRESH_TCHR_3 0x00020000 +#define S3C44B0X_REFRESH_TCHR_4 0x00030000 + +#define S3C44B0X_REFRESH_COUNTER 0x000003FF /* mask for the refresh counter (bit 0-10) */ + +/* BANKSIZE */ +#define S3C44B0X_BANKSIZE_SCLKEN 0x00000010 +#define S3C44B0X_BANKSIZE_BK76MAP_2 0x00000004 +#define S3C44B0X_BANKSIZE_BK76MAP_4 0x00000005 +#define S3C44B0X_BANKSIZE_BK76MAP_8 0x00000006 +#define S3C44B0X_BANKSIZE_BK76MAP_16 0x00000007 +#define S3C44B0X_BANKSIZE_BK76MAP_32 0x00000000 + +/* MRSRB */ +#define S3C44B0X_MRSRB_WBL 0x00000200 +#define S3C44B0X_MRSRB_CL_1 0x00000000 +#define S3C44B0X_MRSRB_CL_2 0x00000020 +#define S3C44B0X_MRSRB_CL_3 0x00000030 +#define S3C44B0X_MRSRB_BT_SEQ 0x00000000 +#define S3C44B0X_MRSRB_BT_NONSEQ 0x00000008 +#define S3C44B0X_MRSRB_BL_1 0x00000000 + + /************/ + /*** UART ***/ + /************/ + +#define S3C44B0X_ULCON0 0x01d00000 +#define S3C44B0X_UCON0 0x01d00004 +#define S3C44B0X_UFCON0 0x01d00008 +#define S3C44B0X_UMCON0 0x01d0000c +#define S3C44B0X_UTRSTAT0 0x01d00010 +#define S3C44B0X_UERSTAT0 0x01d00014 +#define S3C44B0X_UFSTAT0 0x01d00018 +#define S3C44B0X_UMSTAT0 0x01d0001c + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define S3C44B0X_UTXH0 0x01d00023 +#define S3C44B0X_URXH0 0x01d00027 +#else +#define S3C44B0X_UTXH0 0x01d00020 +#define S3C44B0X_URXH0 0x01d00024 +#endif + +#define S3C44B0X_UBRDIV0 0x01d00028 + +#define S3C44B0X_ULCON1 0x01d04000 +#define S3C44B0X_UCON1 0x01d04004 +#define S3C44B0X_UFCON1 0x01d04008 +#define S3C44B0X_UMCON1 0x01d0400c +#define S3C44B0X_UTRSTAT1 0x01d04010 +#define S3C44B0X_UERSTAT1 0x01d04014 +#define S3C44B0X_UFSTAT1 0x01d04018 +#define S3C44B0X_UMSTAT1 0x01d0401c + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define S3C44B0X_UTXH1 0x01d04023 +#define S3C44B0X_URXH1 0x01d04027 +#else +#define S3C44B0X_UTXH1 0x01d04020 +#define S3C44B0X_URXH1 0x01d04024 +#endif + +#define S3C44B0X_UBRDIV1 0x01d04028 + +/* ULCON */ +#define S3C44B0X_ULCON_IR 0x00000040 + +#define S3C44B0X_ULCON_PAR_NO 0x00000000 +#define S3C44B0X_ULCON_PAR_ODD 0x00000020 +#define S3C44B0X_ULCON_PAR_EVEN 0x00000028 +#define S3C44B0X_ULCON_PAR_1 0x00000030 +#define S3C44B0X_ULCON_PAR_0 0x00000038 + +#define S3C44B0X_ULCON_STOPB_1 0x00000000 +#define S3C44B0X_ULCON_STOPB_2 0x00000004 + +#define S3C44B0X_ULCON_WORDLN_5 0x00000000 +#define S3C44B0X_ULCON_WORDLN_6 0x00000001 +#define S3C44B0X_ULCON_WORDLN_7 0x00000002 +#define S3C44B0X_ULCON_WORDLN_8 0x00000003 + +/* UCON */ +#define S3C44B0X_UCON_TXINT_LEVEL 0x00000200 +#define S3C44B0X_UCON_RXINT_LEVEL 0x00000100 +#define S3C44B0X_UCON_TXINT_PULSE 0x00000000 +#define S3C44B0X_UCON_RXINT_PULSE 0x00000000 +#define S3C44B0X_UCON_RX_TIMEOUT_EN 0x00000080 +#define S3C44B0X_UCON_RX_ERR_INT_EN 0x00000040 +#define S3C44B0X_UCON_LOOP 0x00000020 +#define S3C44B0X_UCON_SEND_BREAK 0x00000010 + +#define S3C44B0X_UCON_TX_DIS 0x00000000 +#define S3C44B0X_UCON_TX_MODE_INT_POLL 0x00000004 +#define S3C44B0X_UCON_TX_MODE_BDMA0 0x00000008 +#define S3C44B0X_UCON_TX_MODE_BDMA1 0x0000000c + +#define S3C44B0X_UCON_RX_DIS 0x00000000 +#define S3C44B0X_UCON_RX_MODE_INT_POLL 0x00000001 +#define S3C44B0X_UCON_RX_MODE_BDMA0 0x00000002 +#define S3C44B0X_UCON_RX_MODE_BDMA1 0x00000003 + +/* UFCON */ +#define S3C44B0X_UFCON_TX_FIFO_0 0x00000000 /* TX FIFO byte size */ +#define S3C44B0X_UFCON_TX_FIFO_4 0x00000040 +#define S3C44B0X_UFCON_TX_FIFO_8 0x00000080 +#define S3C44B0X_UFCON_TX_FIFO_12 0x000000c0 + +#define S3C44B0X_UFCON_RX_FIFO_4 0x00000000 /* RX FIFO byte size */ +#define S3C44B0X_UFCON_RX_FIFO_8 0x00000010 +#define S3C44B0X_UFCON_RX_FIFO_12 0x00000020 +#define S3C44B0X_UFCON_RX_FIFO_16 0x00000030 + +#define S3C44B0X_UFCON_TX_FIFO_RST 0x00000004 +#define S3C44B0X_UFCON_RX_FIFO_RST 0x00000002 +#define S3C44B0X_UFCON_FIFO_EN 0x00000001 /* global FIFO enable */ + +/* UMCON */ +#define S3C44B0X_UMCON_AFC 0x00000010 /* auto flow control */ +#define S3C44B0X_UMCON_RQST_SEND 0x00000001 /* request to send 1=L(active RTS) 0=H(inactive RTS) */ + +/* UTRSTAT */ +#define S3C44B0X_UTRSTAT_TSE 0x00000004 /* transmitter shifter empty */ +#define S3C44B0X_UTRSTAT_TBE 0x00000002 /* transmitt buffer empty */ +#define S3C44B0X_UTRSTAT_RBDR 0x00000001 /* receive buffer data ready */ + +/* UERSTAT */ +#define S3C44B0X_UERSTAT_BREAK_DETECT 0x00000008 +#define S3C44B0X_UERSTAT_FRAME_ERROR 0x00000004 +#define S3C44B0X_UERSTAT_PARITY_ERROR 0x00000002 +#define S3C44B0X_UERSTAT_OVERRUN_ERROR 0x00000001 + +/* UFSTAT */ +#define S3C44B0X_UFSTAT_TX_FIFO_FULL 0x00000200 +#define S3C44B0X_UFSTAT_RX_FIFO_FULL 0x00000100 +#define S3C44B0X_UFSTAT_TX_FIFO_COUNT 0x000000F0 +#define S3C44B0X_UFSTAT_RX_FIFO_COUNT 0x0000000F + + /***********/ + /*** SIO ***/ + /***********/ + +#define S3C44B0X_SIOCON 0x01d14000 +#define S3C44B0X_SIODAT 0x01d14004 +#define S3C44B0X_SBRDR 0x01d14008 +#define S3C44B0X_ITVCNT 0x01d1400c +#define S3C44B0X_DNCTZ 0x01d14010 + + /****************************/ + /*** IIS (Inter IC Sound) ***/ + /****************************/ + +#define S3C44B0X_IISCON 0x01d18000 +#define S3C44B0X_IISMOD 0x01d18004 +#define S3C44B0X_IISPSR 0x01d18008 +#define S3C44B0X_IISFIFCON 0x01d1800c +#define S3C44B0X_IISFIF 0x01d18010 + + /*****************/ + /*** I/O ports ***/ + /*****************/ + +#define S3C44B0X_PCONA 0x01d20000 +#define S3C44B0X_PDATA 0x01d20004 +#define S3C44B0X_PCONB 0x01d20008 +#define S3C44B0X_PDATB 0x01d2000c + +#define S3C44B0X_PCONC 0x01d20010 +#define S3C44B0X_PDATC 0x01d20014 +#define S3C44B0X_PUPC 0x01d20018 +#define S3C44B0X_PCOND 0x01d2001c +#define S3C44B0X_PDATD 0x01d20020 +#define S3C44B0X_PUPD 0x01d20024 +#define S3C44B0X_PCONE 0x01d20028 +#define S3C44B0X_PDATE 0x01d2002c +#define S3C44B0X_PUPE 0x01d20030 +#define S3C44B0X_PCONF 0x01d20034 +#define S3C44B0X_PDATF 0x01d20038 +#define S3C44B0X_PUPF 0x01d2003c +#define S3C44B0X_PCONG 0x01d20040 +#define S3C44B0X_PDATG 0x01d20044 +#define S3C44B0X_PUPG 0x01d20048 +#define S3C44B0X_SPUCR 0x01d2004c + + /***************************/ + /*** external interrupts ***/ + /***************************/ + +#define S3C44B0X_EXTINT 0x01d20050 +#define S3C44B0X_EXTINPND 0x01d20054 + + /**********************/ + /*** WATCHDOG TIMER ***/ + /**********************/ + +#define S3C44B0X_WTCON 0x01d30000 +#define S3C44B0X_WTDAT 0x01d30004 +#define S3C44B0X_WTCNT 0x01d30008 + + /*********************/ + /*** A/D CONVERTER ***/ + /*********************/ + +#define S3C44B0X_ADCCON 0x01d40000 +#define S3C44B0X_ADCPSR 0x01d40004 +#define S3C44B0X_ADCDAT 0x01d40008 + + /*****************/ + /*** PWM TIMER ***/ + /*****************/ + +#define S3C44B0X_TCFG0 0x01d50000 /* prescaler configuration */ +#define S3C44B0X_TCFG1 0x01d50004 /* MUX-input for PWM and DMA */ +#define S3C44B0X_TCON 0x01d50008 /* timer control register (start/stop, PWM-out, auto-reload, dead-zone) */ +#define S3C44B0X_TCNTB0 0x01d5000c /* timer counter "buffer" register (read-write) to update the timer counter */ +#define S3C44B0X_TCMPB0 0x01d50010 /* timer compare register */ +#define S3C44B0X_TCNTO0 0x01d50014 /* timer counter "observation" register (real counter value, read-only) */ +#define S3C44B0X_TCNTB1 0x01d50018 +#define S3C44B0X_TCMPB1 0x01d5001c +#define S3C44B0X_TCNTO1 0x01d50020 +#define S3C44B0X_TCNTB2 0x01d50024 +#define S3C44B0X_TCMPB2 0x01d50028 +#define S3C44B0X_TCNTO2 0x01d5002c +#define S3C44B0X_TCNTB3 0x01d50030 +#define S3C44B0X_TCMPB3 0x01d50034 +#define S3C44B0X_TCNTO3 0x01d50038 +#define S3C44B0X_TCNTB4 0x01d5003c +#define S3C44B0X_TCMPB4 0x01d50040 +#define S3C44B0X_TCNTO4 0x01d50044 +#define S3C44B0X_TCNTB5 0x01d50048 +#define S3C44B0X_TCNTO5 0x01d5004c + +/* TCON */ +#define S3C44B0X_TCON_T5_AUTO 0x04000000 /* automatically reload the timer register (cycle) */ +#define S3C44B0X_TCON_T5_MAN_UPDATE 0x02000000 /* manualy update the counter (read from TCNTBn) */ +#define S3C44B0X_TCON_T5_START 0x01000000 /* start the timer (normal modus) if bit not set -> no decrement of counter */ + +#define S3C44B0X_TCON_T4_AUTO 0x00800000 +#define S3C44B0X_TCON_T4_OUTPUT 0x00400000 /* enable output to the PWM-pin (controlled by TCMPBn and TCNTBn) */ +#define S3C44B0X_TCON_T4_MAN_UPDATE 0x00200000 +#define S3C44B0X_TCON_T4_START 0x00100000 + +#define S3C44B0X_TCON_T3_AUTO 0x00080000 +#define S3C44B0X_TCON_T3_OUTPUT 0x00040000 +#define S3C44B0X_TCON_T3_MAN_UPDATE 0x00020000 +#define S3C44B0X_TCON_T3_START 0x00010000 + +#define S3C44B0X_TCON_T2_AUTO 0x00008000 +#define S3C44B0X_TCON_T2_OUTPUT 0x00004000 +#define S3C44B0X_TCON_T2_MAN_UPDATE 0x00002000 +#define S3C44B0X_TCON_T2_START 0x00001000 + +#define S3C44B0X_TCON_T1_AUTO 0x00000800 +#define S3C44B0X_TCON_T1_OUTPUT 0x00000400 +#define S3C44B0X_TCON_T1_MAN_UPDATE 0x00000200 +#define S3C44B0X_TCON_T1_START 0x00000100 + +#define S3C44B0X_TCON_DEAD_ZONE_EN 0x00000010 /* enable the dead zone for PWM-mode */ + +#define S3C44B0X_TCON_T0_AUTO 0x00000008 +#define S3C44B0X_TCON_T0_OUTPUT 0x00000004 +#define S3C44B0X_TCON_T0_MAN_UPDATE 0x00000002 +#define S3C44B0X_TCON_T0_START 0x00000001 + + /***********/ + /*** IIC ***/ + /***********/ + +#define S3C44B0X_IICCON 0x01d60000 +#define S3C44B0X_IICSTAT 0x01d60004 +#define S3C44B0X_IICADD 0x01d60008 +#define S3C44B0X_IICDS 0x01d6000c + + /***********/ + /*** RTC ***/ + /***********/ + +#define S3C44B0X_RTCCON 0x01d70040 +#define S3C44B0X_RTCALM 0x01d70050 +#define S3C44B0X_ALMSEC 0x01d70054 +#define S3C44B0X_ALMMIN 0x01d70058 +#define S3C44B0X_ALMHOUR 0x01d7005c +#define S3C44B0X_ALMDAY 0x01d70060 +#define S3C44B0X_ALMMON 0x01d70064 +#define S3C44B0X_ALMYEAR 0x01d70068 +#define S3C44B0X_RTCRST 0x01d7006c +#define S3C44B0X_BCDSEC 0x01d70070 +#define S3C44B0X_BCDMIN 0x01d70074 +#define S3C44B0X_BCDHOUR 0x01d70078 +#define S3C44B0X_BCDDAY 0x01d7007c +#define S3C44B0X_BCDDATE 0x01d70080 +#define S3C44B0X_BCDMON 0x01d70084 +#define S3C44B0X_BCDYEAR 0x01d70088 +#define S3C44B0X_TICINT 0x01d7008c + + /********************************/ + /*** CLOCK & POWER MANAGEMENT ***/ + /********************************/ + +#define S3C44B0X_PLLCON 0x01d80000 +#define S3C44B0X_CLKCON 0x01d80004 +#define S3C44B0X_CLKSLOW 0x01d80008 +#define S3C44B0X_LOCKTIME 0x01d8000c + +#define S3C44B0X_CLKCON_IIS 0x4000 +#define S3C44B0X_CLKCON_IIC 0x2000 +#define S3C44B0X_CLKCON_ADC 0x1000 +#define S3C44B0X_CLKCON_RTC 0x0800 +#define S3C44B0X_CLKCON_GPIO 0x0400 +#define S3C44B0X_CLKCON_UART1 0x0200 +#define S3C44B0X_CLKCON_UART0 0x0100 +#define S3C44B0X_CLKCON_BDMA 0x0080 +#define S3C44B0X_CLKCON_LCDC 0x0040 +#define S3C44B0X_CLKCON_SIO 0x0020 +#define S3C44B0X_CLKCON_ZDMA 0x0010 +#define S3C44B0X_CLKCON_PWMTIMER 0x0008 +#define S3C44B0X_CLKCON_IDLE_BIT 0x0004 +#define S3C44B0X_CLKCON_SL_IDLE 0x0002 +#define S3C44B0X_CLKCON_STOP_BIT 0x0001 + +#define S3C44B0X_CLKSLOW_PLL_OFF 0x00000010 +#define S3C44B0X_CLKSLOW_SLOW_BIT 0x00000008 +#define S3C44B0X_CLKSLOW_VAL_0 0x00000000 +#define S3C44B0X_CLKSLOW_VAL_1 0x00000001 +#define S3C44B0X_CLKSLOW_VAL_2 0x00000002 +#define S3C44B0X_CLKSLOW_VAL_3 0x00000003 + + /****************************/ + /*** INTERRUPT CONTROLLER ***/ + /****************************/ + +#define S3C44B0X_INTCON 0x01e00000 +#define S3C44B0X_INTPND 0x01e00004 +#define S3C44B0X_INTMOD 0x01e00008 +#define S3C44B0X_INTMSK 0x01e0000c +#define S3C44B0X_I_PSLV 0x01e00010 +#define S3C44B0X_I_PMST 0x01e00014 +#define S3C44B0X_I_CSLV 0x01e00018 +#define S3C44B0X_I_CMST 0x01e0001c +#define S3C44B0X_I_ISPR 0x01e00020 +#define S3C44B0X_I_ISPC 0x01e00024 +#define S3C44B0X_F_ISPR 0x01e00038 +#define S3C44B0X_F_ISPC 0x01e0003c + + /***********/ + /*** DMA ***/ + /***********/ + +#define S3C44B0X_ZDCON0 0x01e80000 +#define S3C44B0X_ZDISRC0 0x01e80004 +#define S3C44B0X_ZDIDES0 0x01e80008 +#define S3C44B0X_ZDICNT0 0x01e8000c +#define S3C44B0X_ZDCSRC0 0x01e80010 +#define S3C44B0X_ZDCDES0 0x01e80014 +#define S3C44B0X_ZDCCNT0 0x01e80018 +#define S3C44B0X_ZDCON1 0x01e80020 +#define S3C44B0X_ZDISRC1 0x01e80024 +#define S3C44B0X_ZDIDES1 0x01e80028 +#define S3C44B0X_ZDICNT1 0x01e8002c +#define S3C44B0X_ZDCSRC1 0x01e80030 +#define S3C44B0X_ZDCDES1 0x01e80034 +#define S3C44B0X_ZDCCNT1 0x01e80038 + +#define S3C44B0X_BDCON0 0x01f80000 +#define S3C44B0X_BDISRC0 0x01f80004 +#define S3C44B0X_BDIDES0 0x01f80008 +#define S3C44B0X_BDICNT0 0x01f8000c +#define S3C44B0X_BDCSRC0 0x01f80010 +#define S3C44B0X_BDCDES0 0x01f80014 +#define S3C44B0X_BDCCNT0 0x01f80018 +#define S3C44B0X_BDCON1 0x01f80020 +#define S3C44B0X_BDISRC1 0x01f80024 +#define S3C44B0X_BDIDES1 0x01f80028 +#define S3C44B0X_BDICNT1 0x01f8002c +#define S3C44B0X_BDCSRC1 0x01f80030 +#define S3C44B0X_BDCDES1 0x01f80034 +#define S3C44B0X_BDCCNT1 0x01f80038 + +#define S3C44B0X_ZDCON_STE_RDY 0x00000000 +#define S3C44B0X_ZDCON_STE_NTC 0x00000040 +#define S3C44B0X_ZDCON_STE_TC 0x00000080 + +#define S3C44B0X_ZDCON_QDS_EN 0x00000000 +#define S3C44B0X_ZDCON_QDS_DIS 0x0000000c + +#define S3C44B0X_ZDCON_CMD_NONE 0x00000000 +#define S3C44B0X_ZDCON_CMD_START 0x00000001 +#define S3C44B0X_ZDCON_CMD_PAUSE 0x00000002 +#define S3C44B0X_ZDCON_CMD_CANCEL 0x00000003 + + +/********************* + * LCD controller * + *********************/ +#define S3C44B0X_LCD_MEM 0x0c060000 + +#define S3C44B0X_LCDCON1 0x01f00000 +#define S3C44B0X_LCDCON2 0x01f00004 +#define S3C44B0X_LCDCON3 0x01f00040 +#define S3C44B0X_LCDSADDR1 0x01f00008 +#define S3C44B0X_LCDSADDR2 0x01f0000c +#define S3C44B0X_LCDSADDR3 0x01f00010 + +#define S3C44B0X_REDLUT 0x01f00014 +#define S3C44B0X_GREENLUT 0x01f00018 +#define S3C44B0X_BLUELUT 0x01f0001c +#define S3C44B0X_DP1_2 0x01f00020 +#define S3C44B0X_DP4_7 0x01f00024 +#define S3C44B0X_DP3_5 0x01f00028 +#define S3C44B0X_DP2_3 0x01f0002c +#define S3C44B0X_DP5_7 0x01f00030 +#define S3C44B0X_DP3_4 0x01f00034 +#define S3C44B0X_DP4_5 0x01f00038 +#define S3C44B0X_DP6_7 0x01f0003c + +#define S3C44B0X_DITHMODE 0x01f00044 + +/* LCDCON1 */ +#define S3C44B0X_LCDCON1_WLH_4 0x00000000 +#define S3C44B0X_LCDCON1_WLH_8 0x00000400 +#define S3C44B0X_LCDCON1_WLH_12 0x00000800 +#define S3C44B0X_LCDCON1_WLH_16 0x00000c00 + +#define S3C44B0X_LCDCON1_WDLY_4 0x00000000 +#define S3C44B0X_LCDCON1_WDLY_8 0x00000100 +#define S3C44B0X_LCDCON1_WDLY_12 0x00000200 +#define S3C44B0X_LCDCON1_WDLY_16 0x00000300 + +#define S3C44B0X_LCDCON1_MMODE 0x00000080 + +#define S3C44B0X_LCDCON1_DISMODE_4D 0x00000000 +#define S3C44B0X_LCDCON1_DISMODE_4S 0x00000020 +#define S3C44B0X_LCDCON1_DISMODE_8S 0x00000040 + +#define S3C44B0X_LCDCON1_INVCLK 0x00000010 +#define S3C44B0X_LCDCON1_INVLINE 0x00000008 +#define S3C44B0X_LCDCON1_INVFRAME 0x00000004 +#define S3C44B0X_LCDCON1_INVVD 0x00000002 +#define S3C44B0X_LCDCON1_ENVID 0x00000001 + + +/* LCDCON3 */ +#define S3C44B0X_LCDCON3_SELFREFRESH 0x00000001 + + +/* LCDSADDR1 */ +#define S3C44B0X_LCDSADDR1_MONO 0x00000000 +#define S3C44B0X_LCDSADDR1_GRAY_4 0x08000000 +#define S3C44B0X_LCDSADDR1_GRAY_16 0x10000000 +#define S3C44B0X_LCDSADDR1_COLOR 0x18000000 + +/* LCDSADDR2 */ +#define S3C44B0X_LCDSADDR2_BSWP 0x20000000 +#endif /* _S3C44B0X_H_ */ diff --git a/include/asm-arm/arch-s3c44b0x/system.h b/include/asm-arm/arch-s3c44b0x/system.h new file mode 100644 index 00000000..ce3e5567 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/system.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/system.h + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + + +static void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0); +} + +#endif diff --git a/include/asm-arm/arch-s3c44b0x/time.h b/include/asm-arm/arch-s3c44b0x/time.h new file mode 100644 index 00000000..45c9b6d8 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/time.h @@ -0,0 +1,7 @@ +/* + * linux/include/asm-arm/arch-s3c44b0x/time.h + */ + +#ifndef __ASM_ARCH_TIME_H__ +#define __ASM_ARCH_TIME_H__ +#endif diff --git a/include/asm-arm/arch-s3c44b0x/timex.h b/include/asm-arm/arch-s3c44b0x/timex.h new file mode 100644 index 00000000..5527f0f7 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/timex.h @@ -0,0 +1,10 @@ +/* + * linux/include/asm-armnommu/arch-s3c3410/timex.h + */ + +#ifndef __ASM_ARCH_TIMEX_H__ +#define __ASM_ARCH_TIMEX_H__ + +#define CLOCK_TICK_RATE (CONFIG_ARM_CLK) + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/include/asm-arm/arch-s3c44b0x/uncompress.c b/include/asm-arm/arch-s3c44b0x/uncompress.c new file mode 100644 index 00000000..88651556 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/uncompress.c @@ -0,0 +1,23 @@ +/* + * linux/include/asm/arch-samsung/uncompress.c + */ + +#include + +static int s3c44b0x_decomp_setup() +{ +} + +static int s3c44b0x_putc(char c) +{ + while (!(SYSREG_GET(S3C44B0X_UTRSTAT0) & 0x2)); + SYSREG_SETB(S3C44B0X_UTXH0, c); + if(c == '\n') + s3c44b0x_putc('\r'); +} + +static void s3c44b0x_puts(const char *s) +{ + while(*s != '\0') + s3c44b0x_putc(*s++); +} diff --git a/include/asm-arm/arch-s3c44b0x/uncompress.h b/include/asm-arm/arch-s3c44b0x/uncompress.h new file mode 100644 index 00000000..fd5e143e --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/uncompress.h @@ -0,0 +1,51 @@ +/* + * asm/arch/uncompress.c: + * Optional routines to aid in debugging the decompression phase + * of kernel boot. + * copyright: + * (C) 2001 RidgeRun, Inc. (http://www.ridgerun.com) + * author: Gordon McNutt + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +/* + * This is used by arch/armnommu/boot/compressed/misc.c to write progress info + * out the serial port so that the user can see debug messages up to the point + * where the kernel is decompressed. The STANDALONE_DEBUG macro chooses between + * this and the standard printf. Punt. + * --gmcnutt + */ +#define puts(s) s3c44b0x_puts(s) + +/* + * Not sure what this is for. Probably an optional watchdog to check if the + * decompress got hung so we can warn the user. Punt. + */ +#define arch_decomp_wdog() + +/* + * If we need to do some setup prior to decompression (like initializing the + * UART if we want to use puts() above) then we define it here. Punt. + */ +#define arch_decomp_setup() s3c44b0x_decomp_setup() diff --git a/include/asm-arm/arch-s3c44b0x/vmalloc.h b/include/asm-arm/arch-s3c44b0x/vmalloc.h new file mode 100644 index 00000000..a4d533a0 --- /dev/null +++ b/include/asm-arm/arch-s3c44b0x/vmalloc.h @@ -0,0 +1,18 @@ +/* + * linux/include/asm-armnommu/arch-s3c44b0x/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_S3C44B0X_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_S3C44B0X_SDRAM_SIZE) diff --git a/include/asm-arm/arch-s5c7375/blkmem.h b/include/asm-arm/arch-s5c7375/blkmem.h new file mode 100644 index 00000000..435191bf --- /dev/null +++ b/include/asm-arm/arch-s5c7375/blkmem.h @@ -0,0 +1,25 @@ +/* + * linux/include/asm-armnommu/arch-s5c7375/blkmem.h + * + * Copyright (c) 2003 Hyok S. Choi, Samsung Electronics Co.,Ltd. + * + * + * Contains configuration settings for the blkmem driver. + */ +#ifndef __ASM_ARCH_BLKMEM_H +#define __ASM_ARCH_BLKMEM_H + +#define CAT_ROMARRAY + + +#ifndef HYOK_ROMFS_BOOT + extern char _end[]; + #define FIXUP_ARENAS \ + arena[0].address = ((unsigned long)_end + DRAM_BASE + 0x2000); // ram +#else + extern char __bss_start[]; + #define FIXUP_ARENAS \ + arena[0].address = ((unsigned long)__bss_start + FLASH_MEM_BASE); // rom +#endif + +#endif diff --git a/include/asm-arm/arch-s5c7375/dma.h b/include/asm-arm/arch-s5c7375/dma.h new file mode 100644 index 00000000..2962d75a --- /dev/null +++ b/include/asm-arm/arch-s5c7375/dma.h @@ -0,0 +1,140 @@ +/* + * linux/include/asm-arm/arch-s5c7375/dma-s5c7375.h + * Generic S5C7375 DMA support + * Copyright (C) 2002 SW.LEE + * Copyright (C) 2003 Hyok S. Choi + */ + +#include +#include + +#ifndef __ASM_S5C7375_ARCH_DMA_H +#define __ASM_S5C7375_ARCH_DMA_H + +/* + * This is the maximum DMA address(physical address) that can be DMAd to. + * + */ +#define MAX_DMA_ADDRESS 0x20000000 +#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ + +/* + * The regular generic DMA interface is inappropriate for the + * S5C7375 DMA model. None of the S5C7375 specific drivers using + * DMA are portable anyway so it's pointless to try to twist the + * regular DMA API to accommodate them. + */ + +/***************************************************************************/ +/* this means that We will use arch/arm/mach/dma.h i.e generic dma module */ +#define MAX_DMA_CHANNELS 0 +/****************************************************************************/ + +/* + * The S5C7375 has four internal DMA channels. + */ +#define S5C7375_DMA_CHANNELS 6 + +#define MAX_S5C7375_DMA_CHANNELS S5C7375_DMA_CHANNELS + + +/* + * All possible S5C7375 devices the specific DMA channel can be attached to. + * I'm sorry for only DMA Device Address + * DMA request sources would be controlled by H/W DMA mode selected by DCON register + */ + +typedef enum { + DMA0_SOURCE0 , /* EXT device 0 */ + DMA0_SOURCE1 , /* UART1 */ + DMA0_SOURCE2 , /* USB */ + DMA0_SOURCE3 , /* PPIC */ + DMA0_SOURCE4 , /* UART0 */ + DMA0_SOURCE5 , /* EXT device 1 */ +} dma_device_t; + + +/* + * DMA buffer structure + */ + +typedef struct dma_buf_s { + int size; /* buffer size */ + dma_addr_t dma_start; /* starting DMA address */ + dma_addr_t dma_ptr; /* next DMA pointer to use */ + int ref; /* number of DMA references */ + void *id; /* to identify buffer from outside */ + struct dma_buf_s *next; /* next buffer to process */ +} dma_buf_t; + + +/* + * DMA channel structure. + */ + +/* + * DMA control register structure + * one channel S5C7375 DMA control register is 0x40 byte + * + */ + +typedef void (*dma_callback_t)( void *buf_id, int size); + +typedef struct { + volatile u_long DISRC; + volatile u_long DISRCC; + volatile u_long DIDST; + volatile u_long DIDSTC; + volatile u_long DCON; + volatile u_long DSTAT; + volatile u_long DCSRC; + volatile u_long DCDST; + volatile u_long DMASKTRIG; +} dma_regs_t; + +#define DOUBLE_BUFFER_COUNT 3 +typedef struct { + unsigned int in_use; /* Device is allocated */ + const char *device_id; /* Device name */ + dma_device_t device; /* ... to which this channel is attached */ + dma_buf_t *head; /* where to insert buffers */ + dma_buf_t *tail; /* where to remove buffers */ + dma_buf_t *curr; /* buffer currently DMA'ed */ + int stopped; /* 1 if DMA is stalled */ + dma_regs_t *regs; /* points to appropriate DMA registers */ + int irq; /* IRQ used by the channel */ + dma_callback_t callback; /* ... to call when buffers are done */ + + unsigned int queueCnt; + unsigned int usedQueueCnt; + int isSleeping; + int spin_size; /* > 0 when DMA should spin when no more buffer */ + dma_addr_t spin_addr; /* DMA address to spin onto */ + int spin_ref; /* number of spinning references */ + + unsigned char already_init; /* S5C7375 specific */ +} s5c7375_dma_t; + +/* S5C7375 DMA API */ +extern int s5c7375_request_dma( dmach_t channel, const char *device_id, + dma_device_t device ); +extern int s5c7375_dma_set_callback( dmach_t channel, dma_callback_t cb ); +extern int s5c7375_dma_set_spin( dmach_t channel, dma_addr_t addr, int size ); +extern int s5c7375_dma_queue_buffer( dmach_t channel, void *buf_id, + dma_addr_t data, int size ); +extern int s5c7375_dma_get_current( dmach_t channel, void **buf_id, dma_addr_t *addr ); +extern int s5c7375_dma_stop( dmach_t channel ); +extern int s5c7375_dma_resume( dmach_t channel ); +extern int s5c7375_dma_flush_all( dmach_t channel ); +extern void s5c7375_free_dma( dmach_t channel ); +extern int s5c7375_dma_sleep( dmach_t channel ); +extern int s5c7375_dma_wakeup( dmach_t channel ); +extern void s5c7375_dma_done (s5c7375_dma_t *dma); + +#endif /* _ASM_S5C7375_ARCH_DMA_H */ + + + + + + diff --git a/include/asm-arm/arch-s5c7375/entry-macro.S b/include/asm-arm/arch-s5c7375/entry-macro.S new file mode 100644 index 00000000..8adbae38 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/entry-macro.S @@ -0,0 +1,57 @@ +/* + * arch/armnommu/mach-s5c7375/entry-macro.S + * + * Copyright (C) 2003 Hyok S. Choi + * Samsung Electronics Co.,Ltd. + * + * defines machine dependent entry macros. + * included in the arch/armnommu/kernel/entry.S + * + * 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 + */ + +#if defined(CONFIG_ARCH_S5C7375) + .macro disable_fiq + .endm + #if 1 + /* r0 r6 r5 lr */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =(rINTBase + 0x3C) @ rIRQISPR + ldr \irqstat, [\irqstat, #0] @ load irqstat + + mov \irqnr, #0 +1001: + tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #NR_IRQS + bcc 1001b +1002: /* EQ will be set if we reach 32 */ + .endm + + #else /* for better performance */ + + /* r0 r6 r5 lr */ + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =(rINTBase + 0x78) @ rIVEC_ADDR + ldr \irqnr, [\irqstat] @ load irqnr * 4 + mov \irqnr, \irqnr, lsr #2 @ irqnr >> 2 + movs \tmp, \irqnr + .endm + #endif + .macro irq_prio_table + .endm +#endif diff --git a/include/asm-arm/arch-s5c7375/hardware.h b/include/asm-arm/arch-s5c7375/hardware.h new file mode 100644 index 00000000..f31a4335 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/hardware.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/arch-s5c7375/hardware.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#ifndef __ASSEMBLY__ + +#define HARD_RESET_NOW() + +/* the machine dependent bootmem reserve and free routines */ +#define MACH_RESERVE_BOOTMEM() do { \ + /* we need to keep the section table for mmu */ \ + reserve_bootmem_node(pgdat, 0x00004000, 0x4000); \ + } while(0) + +#define MACH_FREE_BOOTMEM() + +/* yes, freeing initmem is okay */ +#define DO_FREE_INITMEM() (0) + +#endif + +#endif /* END OF __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-s5c7375/io.h b/include/asm-arm/arch-s5c7375/io.h new file mode 100644 index 00000000..d5d75ab5 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/io.h @@ -0,0 +1,69 @@ +/* + * linux/include/asm-arm/arch-s5c7375/io.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + /* Used in kernel/resource.c */ + +/* + * We have the this routine to use usb host device driver + * + */ + + +#define PCI_IO_VADDR (0x0) +#define PCI_MEMORY_VADDR (0x0) + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + + +/* + * Generic virtual read/write + */ +#if 0 +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#endif +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) (1) + + +/* + * For example, + * CS8900A Net Device Driver + * for asm/io.h + */ +/* +#define __io +*/ + + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) (iomem) + +#endif diff --git a/include/asm-arm/arch-s5c7375/irq.h b/include/asm-arm/arch-s5c7375/irq.h new file mode 100644 index 00000000..2afb4ad2 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/irq.h @@ -0,0 +1,40 @@ +/* + * linux/include/asm-arm/arch-s5c7375/irq.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.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 + */ +#ifndef __S5C7375_irq_h +#define __S5C7375_irq_h + +#include +#include +#include +#include + +/* To understand S5C7375 irq + * Look hard at "fixup_irq definition in irq.c file " + */ +extern unsigned int fixup_irq(int i); + +extern void do_IRQ(int irq, struct pt_regs *regs); + +extern void s5c7375_init_irq(void); + +#define irq_init_irq s5c7375_init_irq + +#endif diff --git a/include/asm-arm/arch-s5c7375/irqs.h b/include/asm-arm/arch-s5c7375/irqs.h new file mode 100644 index 00000000..d0186b1f --- /dev/null +++ b/include/asm-arm/arch-s5c7375/irqs.h @@ -0,0 +1,124 @@ +/* + * linux/include/asm-arm/arch-s5c7375/irqs.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONIS + * Hyok S. Choi + * + * 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 + */ + +#ifndef __S5C7375_irqs_h +#define __S5C7375_irqs_h 1 + + #define iSRAMBase 0x06000000 // internal SRAM base address + #define iSRAMTop 0x06001FFC // top address of interanl SRAM + #define SDRAMBase 0x00000000 + #define SDRAMTop 0x003FFFFC + +#define SHORTNUMOFINT + /* the number of interrupt source */ + #ifdef SHORTNUMOFINT + #define NumOfInt 16 + #else + #define NumOfInt 32 + #endif + /* for compatibility for linux */ + #define NR_IRQS (NumOfInt) + + /* Interrupt Vector table address */ +#ifdef SHORTNUMOFINT + #define IntVectorTable iSRAMTop-(NumOfInt << 3) //internal SRAM area +#else + #define IntVectorTable iSRAMTop-(NumOfInt << 2) //internal SRAM area +#endif + #define IntVectorTableEnd iSRAMTop + //#define IntVectorTable SDRAMTop-(NumOfInt << 2) //SDRAM area + //#define IntVectorTableEnd SDRAMTop + + /* + * Interrupt Vector Table + */ + + #define pIVT_TIMER0 (*(volatile unsigned *)(IntVectorTable)) + #define pIVT_TIMER2 (*(volatile unsigned *)(IntVectorTable+0x04)) + #define pIVT_TIMER3 (*(volatile unsigned *)(IntVectorTable+0x08)) + #define pIVT_USB (*(volatile unsigned *)(IntVectorTable+0x0C)) + #define pIVT_TIMER4 (*(volatile unsigned *)(IntVectorTable+0x10)) // ADD BY HIS + #define pIVT_DMA (*(volatile unsigned *)(IntVectorTable+0x14)) + #define pIVT_TIMER1 (*(volatile unsigned *)(IntVectorTable+0x18)) + #define pIVT_I2C (*(volatile unsigned *)(IntVectorTable+0x1C)) + #define pIVT_COMMRX (*(volatile unsigned *)(IntVectorTable+0x20)) + #define pIVT_COMMTX (*(volatile unsigned *)(IntVectorTable+0x24)) + #define pIVT_GPIO (*(volatile unsigned *)(IntVectorTable+0x28)) + #define pIVT_EXT0 (*(volatile unsigned *)(IntVectorTable+0x2C)) + #define pIVT_EXT1 (*(volatile unsigned *)(IntVectorTable+0x30)) + #define pIVT_EXT2 (*(volatile unsigned *)(IntVectorTable+0x34)) + #define pIVT_EXT3 (*(volatile unsigned *)(IntVectorTable+0x38)) + + + /* + * define the interrupt source corresponing to each interrupt register bits + */ + + #define INT_TIMER0 0x00000001 + #define INT_TIMER2 0x00000002 + #define INT_TIMER3 0x00000004 + #define INT_USB 0x00000008 + #define INT_TIMER4 0x00000010 + #define INT_DMA 0x00000020 + #define INT_TIMER1 0x00000040 + #define INT_I2C 0x00000080 + #define INT_COMMRX 0x00000100 + #define INT_COMMTX 0x00000200 + #define INT_GPIO 0x00000400 + #define INT_EXT0 0x00000800 + #define INT_EXT1 0x00001000 + #define INT_EXT2 0x00002000 + #define INT_EXT3 0x00004000 + + #define INT_N_TIMER0 0 + #define INT_N_TIMER2 1 + #define INT_N_TIMER3 2 + #define INT_N_USB 3 + #define INT_N_TIMER4 4 + #define INT_N_DMA 5 + #define INT_N_TIMER1 6 + #define INT_N_I2C 7 + #define INT_N_COMMRX 8 + #define INT_N_COMMTX 9 + #define INT_N_GPIO 10 + #define INT_N_EXT0 11 + #define INT_N_EXT1 12 + #define INT_N_EXT2 13 + #define INT_N_EXT3 14 + + + + #define EnableFIQ() (rINTCON = ((rINTCON) & (0x0E))) + #define DisableFIQ() (rINTCON = ((rINTCON) | (0x01))) + + #define EnableIRQ() (rINTCON = ((rINTCON )& (0x0D))) + #define DisableIRQ() (rINTCON = ((rINTCON) | (0x02))) + + #define EnableGMask() (rINTCON = ((rINTCON) | (0x08))) + #define DisableGMask() (rINTCON = ((rINTCON) & (0x07))) + + #define EnableInt(x) (rINTMSK = ((rINTMSK) & (~(x)))) + #define DisableInt(x) (rINTMSK = ((rINTMSK) | (x))) + + +// #define OS_TIMER INT_TIMER4 // used in irq.c? + +#endif /* End of __irqs_h */ diff --git a/include/asm-arm/arch-s5c7375/memory.h b/include/asm-arm/arch-s5c7375/memory.h new file mode 100644 index 00000000..92541809 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/memory.h @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-s5c7375/memory.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define TASK_SIZE (0x01a00000UL) +#define TASK_SIZE_26 TASK_SIZE + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ + +#define PHYS_OFFSET (CONFIG_DRAM_BASE) +#define PAGE_OFFSET (PHYS_OFFSET) +#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE) + +#define __virt_to_phys(vpage) ((unsigned long) (vpage)) +#define __phys_to_virt(ppage) ((unsigned long) (ppage)) +#define __virt_to_bus(vpage) ((unsigned long) (vpage)) +#define __bus_to_virt(ppage) ((unsigned long) (ppage)) + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-s5c7375/param.h b/include/asm-arm/arch-s5c7375/param.h new file mode 100644 index 00000000..8a1d92b2 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/param.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_ASM_PARAM_H__ +#define __ARCH_ASM_PARAM_H__ + +/* nothing for now */ + +#endif /* __ARCH_ASM_PARAM_H__ */ diff --git a/include/asm-arm/arch-s5c7375/s5c7375.h b/include/asm-arm/arch-s5c7375/s5c7375.h new file mode 100644 index 00000000..c7166579 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/s5c7375.h @@ -0,0 +1,384 @@ +/* + * linux/include/asm-arm/arch-s5c7375/s5c7375.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi (hyok.choi@samsung.com) + * + */ + +#ifndef __S5C7375_H +#define __S5C7375_H + +/* keywoard : ClockParameter */ +#define FCLK 162000000 +#define ECLK 27000000 +#define BUSWIDTH (32) + + +/* keywoard : Phy2Vir */ +#define S5C7375_MEM_SIZE (CONFIG_DRAM_SIZE) +#define MEM_SIZE S5C7375_MEM_SIZE + +#define PA_SDRAM_BASE CONFIG_DRAM_BASE/* used in asm/arch/arch.c */ + +#ifndef HYOK_ROMFS_BOOT +#define ZIP_RAMDISK_SIZE (256*1024) /* used in asm/arch/arch.c */ +#define RAMDISK_DN_ADDR (PA_SDRAM_BASE + 0x00400000 - ZIP_RAMDISK_SIZE) /* used in asm/arch/arch.c */ +#else +#define ZIP_RAMDISK_SIZE (0x00040000) /* used in asm/arch/arch.c */ +#define RAMDISK_DN_ADDR (0x00400000 - ZIP_RAMDISK_SIZE) +#endif + +/* if CONFIG_BLK_DEV_RAM_SIZE not defined */ +#define BLK_DEV_RAM_SIZE (256*1024) + + #define rSCRBase 0x40000000 /* base of the System Configuration register */ + #define rASICBase 0x0C000000 /* base of all I/O module register */ + #define rPTEAKBase 0x08F00000 /* preload TeakLite base address */ + + + /* define the base of each I/O devices */ + #define rARM920T rASICBase + #define rMEMBase (rASICBase+0x10000) /* Memory controller */ + #define rDMABase (rASICBase+0x20000) /* DMA controller */ + #define rLCDBase (rASICBase+0x30000) /* LCD controller */ + #define rEMACBase (rASICBase+0x40000) /* Ethernet MAC controller */ + #define rXMEMBase (rASICBase+0x50000) /* TeakLite X memory(16KB) */ + #define rYMEMBase (rASICBase+0x60000) /* TeakLite Y memory(8KB) */ + #define rPMEMBase (rASICBase+0x70000) /* TeakLite P memory(32KB) */ + #define rAPBBase (rASICBase+0x80000) /* AHB2APB bridge */ + + /* Preload TeakLite address */ + #define rPPDataArea (rPTEAKBase+0x00) /* preload TeakLite P data area */ + #define rPXDataArea (rPTEAKBase+0x40000)/* preload TeakLite X data area */ + #define rPYDataArea (rPTEAKBase+0x60000)/* preload TeakLite Y data area */ + + /************ AHB2APB bridge I/O device register *************/ + #define rBRIDGEBase (rAPBBase+0x000) /* APB Bridge interface */ + #define rSCIBase (rAPBBase+0x400) /* Smart card interface */ + #define rUSBBase (rAPBBase+0x5800) /* USB */ + #define rPPIBase (rAPBBase+0xC00) /* IEE1284, Parallel port */ + #define rIICBase (rAPBBase+0x1000) /* IIC */ + #define rTIMEBase (rAPBBase+0x1400) /* Timer */ + #define rRTCBase (rAPBBase+0x1800) /* Real time clock */ + #define rWDTBase (rAPBBase+0x1C00) /* Watch Dog Timer */ + #define rIOPBase (rAPBBase+0x2000) /* Programmable I/O port */ + #define rRPCBase (rAPBBase+0x2400) /* Memory remap */ + #define rINTBase (rAPBBase+0x2800) /* Interrupt controller */ + #define rSSPBase (rAPBBase+0x2C00) /* SSP interface */ + #define rKMI0Base (rAPBBase+0x3000) /* KMI0 */ + #define rUART0Base (rAPBBase+0x3400) /* UART0 */ + #define rUART1Base (rAPBBase+0x3800) /* UART1 */ + #define rPMBase (rAPBBase+0x3C00) /* Power manager */ + #define rTEAKBase (rAPBBase+0x4000) /* Teaklite Z space */ + #define rKMI1Base (rAPBBase+0x4800) /* KMI1 */ + #define rMISCBase (rAPBBase+0x4C00) /* Miscellaneous */ + #define rEXT0Base (rAPBBase+0x5000) /* External 0 */ + #define rEXT1Base (rAPBBase+0x5400) /* External 1 */ + #define rEXT2Base (rAPBBase+0x5800) /* External 2 */ + #define rEXT3Base (rAPBBase+0x5C00) /* External 3 */ + #define rPCMCIABase (rAPBBase+0x9000) /* Programmable I/O port */ + + /* Memory Controller(32bit)*/ + #define rSDRAMCFG0 (*(volatile unsigned *)(rMEMBase+0x00)) /* SDRAM config0 register */ + #define rSDRAMCFG1 (*(volatile unsigned *)(rMEMBase+0x04)) /* SDRAM config1 register */ + #define rSDRAMRefresh (*(volatile unsigned *)(rMEMBase+0x08)) /* SDRAM refresh register */ + #define rSDRAMWB (*(volatile unsigned *)(rMEMBase+0x0C)) /* SDRAM WB timeout register */ + // new static memory controller version + #define rSMCBANK0 (*(volatile unsigned *)(rMEMBase+0x10)) + #define rSMCBANK1 (*(volatile unsigned *)(rMEMBase+0x14)) + #define rSMCBANK2 (*(volatile unsigned *)(rMEMBase+0x18)) + #define rSMCBANK3 (*(volatile unsigned *)(rMEMBase+0x1C)) + + /* DMA Controller(32bit)*/ + // DMA control register + #define rDMACON0 (*(volatile unsigned *)(rDMABase+0x00)) + #define rDMACON1 (*(volatile unsigned *)(rDMABase+0x40)) + #define rDMACON2 (*(volatile unsigned *)(rDMABase+0x80)) + #define rDMACON3 (*(volatile unsigned *)(rDMABase+0xC0)) + #define rDMACON4 (*(volatile unsigned *)(rDMABase+0x100)) + #define rDMACON5 (*(volatile unsigned *)(rDMABase+0x140)) + + // DMA Source Start address register + #define rDMASAR0 (*(volatile unsigned *)(rDMABase+0x04)) + #define rDMASAR1 (*(volatile unsigned *)(rDMABase+0x44)) + #define rDMASAR2 (*(volatile unsigned *)(rDMABase+0x84)) + #define rDMASAR3 (*(volatile unsigned *)(rDMABase+0xC4)) + #define rDMASAR4 (*(volatile unsigned *)(rDMABase+0x104)) + #define rDMASAR5 (*(volatile unsigned *)(rDMABase+0x144)) + + // DMA Destination address register + #define rDMADAR0 (*(volatile unsigned *)(rDMABase+0x08)) + #define rDMADAR1 (*(volatile unsigned *)(rDMABase+0x48)) + #define rDMADAR2 (*(volatile unsigned *)(rDMABase+0x88)) + #define rDMADAR3 (*(volatile unsigned *)(rDMABase+0xC8)) + #define rDMADAR4 (*(volatile unsigned *)(rDMABase+0x108)) + #define rDMADAR5 (*(volatile unsigned *)(rDMABase+0x148)) + + // DMA Terminal Counter register + #define rDMATCR0 (*(volatile unsigned *)(rDMABase+0x0C)) + #define rDMATCR1 (*(volatile unsigned *)(rDMABase+0x4C)) + #define rDMATCR2 (*(volatile unsigned *)(rDMABase+0x8C)) + #define rDMATCR3 (*(volatile unsigned *)(rDMABase+0xCC)) + #define rDMATCR4 (*(volatile unsigned *)(rDMABase+0x10C)) + #define rDMATCR5 (*(volatile unsigned *)(rDMABase+0x14C)) + + // DMA pending & priority register + #define rDMAPRI (*(volatile unsigned *)(rDMABase+0x1F8)) + #define rDMAPND (*(volatile unsigned *)(rDMABase+0x1FC)) + + /* LCD(primecell) Controller(32bit)*/ + + /* APB Base register map */ + /* 1.APB pulse width control register */ + #define rAPBCON0 (*(volatile unsigned *)(rBRIDGEBase+0x00)) + #define rAPBCON1 (*(volatile unsigned *)(rBRIDGEBase+0x04)) + #define rAPBCON2 (*(volatile unsigned *)(rBRIDGEBase+0x08)) + #define rAPBCON3 (*(volatile unsigned *)(rBRIDGEBase+0x0C)) + + /* 2.Smart card interface */ + + + /* 3.USB register(8bit)*/ + + + // Non indexed registers + #define USB_R0 (volatile unsigned *)(rUSBBase+0x00) // 0x00 - Function address register + #define USB_R1 (volatile unsigned *)(rUSBBase+0x04) // 0x01 - Power management register + + #define USB_R2 (volatile unsigned *)(rUSBBase+0x08) // 0x02 - Endpoint interrupt1 register (EP0-EP7) + #define USB_R3 (volatile unsigned *)(rUSBBase+0x0c) // 0x03 - Endpoint interrupt2 register (EP8-EP15) + #define USB_R4 (volatile unsigned *)(rUSBBase+0x10) //- Out interrupt register bank1 + #define USB_R5 (volatile unsigned *)(rUSBBase+0x14) //- Out interrupt register bank2 + #define USB_R6 (volatile unsigned *)(rUSBBase+0x18) // 0x06 - USB interrpt register + + #define USB_R7 (volatile unsigned *)(rUSBBase+0x1C) // 0x07 - Endpoint interrupt enable1 register (EP0-EP7) + #define USB_R8 (volatile unsigned *)(rUSBBase+0x20) // 0x08 - Endpoint interrupt enable2 register (EP8-EP15) + #define USB_R9 (volatile unsigned *)(rUSBBase+0x24) //- Out interrupt enable register bank1 + #define USB_R10 (volatile unsigned *)(rUSBBase+0x28) //- Out interrupt enable register bank2 + #define USB_R11 (volatile unsigned *)(rUSBBase+0x2C) // 0x0B - USB interrupt enable register + + #define USB_R12 (volatile unsigned *)(rUSBBase+0x30) // 0x0C - Frame number1 register + #define USB_R13 (volatile unsigned *)(rUSBBase+0x34) // 0x0D - Frame number2 register + #define USB_R14 (volatile unsigned *)(rUSBBase+0x38) // 0x0E - Index register + + // Common indexed registers + #define USB_IR1 (volatile unsigned *)(rUSBBase+0x40) // 0x10 - Max packet register + + // In indexed registers + #define USB_IR2 (volatile unsigned *)(rUSBBase+0x44) // 0x11 - IN CSR1 register (EP0 CSR register) + #define USB_IR3 (volatile unsigned *)(rUSBBase+0x48) // 0x12 - IN CSR2 register + + // Out indexed registers + #define USB_OR1 (volatile unsigned *)(rUSBBase+0x4C) //- OUT max packet register + #define USB_OR2 (volatile unsigned *)(rUSBBase+0x50) // 0x14 - OUT CSR1 register + #define USB_OR3 (volatile unsigned *)(rUSBBase+0x54) // 0x15 - OUT CSR2 register + #define USB_OR4 (volatile unsigned *)(rUSBBase+0x58) // 0x16 - OUT FIFO write Count1 register + #define USB_OR5 (volatile unsigned *)(rUSBBase+0x5c) // 0x17 - OUT FIFO write Count2 register + + // FIFO registers + #define EP0_FIFO (volatile unsigned *)(rUSBBase+0x80) // 0x20 - EP0 FIFO + #define EP1_FIFO (volatile unsigned *)(rUSBBase+0x84) // 0x21 - EP1 FIFO + #define EP2_FIFO (volatile unsigned *)(rUSBBase+0x88) // 0x22 - EP2 FIFO + #define EP3_FIFO (volatile unsigned *)(rUSBBase+0x8C) // 0x23 - EP3 FIFO + + + /* 4.IEEE 1284(PPI)(8bit)*/ + + /* 5.IIC register(8bit)*/ + /* 6.TIMER register(16bit)*/ + #define rT0CTR (*(volatile int *)(rTIMEBase+0x00)) + #define rT0PSR (*(volatile int *)(rTIMEBase+0x04)) + #define rT0LDR (*(volatile int *)(rTIMEBase+0x08)) + #define rT0ISR (*(volatile int *)(rTIMEBase+0x0C)) + + #define rT1CTR (*(volatile int *)(rTIMEBase+0x10)) + #define rT1PSR (*(volatile int *)(rTIMEBase+0x14)) + #define rT1LDR (*(volatile int *)(rTIMEBase+0x18)) + #define rT1ISR (*(volatile int *)(rTIMEBase+0x1C)) + + #define rT2CTR (*(volatile int *)(rTIMEBase+0x20)) + #define rT2PSR (*(volatile int *)(rTIMEBase+0x24)) + #define rT2LDR (*(volatile int *)(rTIMEBase+0x28)) + #define rT2ISR (*(volatile int *)(rTIMEBase+0x2C)) + + #define rT3CTR (*(volatile int *)(rTIMEBase+0x30)) + #define rT3PSR (*(volatile int *)(rTIMEBase+0x34)) + #define rT3LDR (*(volatile int *)(rTIMEBase+0x38)) + #define rT3ISR (*(volatile int *)(rTIMEBase+0x3C)) + + #define rT4CTR (*(volatile int *)(rTIMEBase+0x40)) + #define rT4PSR (*(volatile int *)(rTIMEBase+0x44)) + #define rT4LDR (*(volatile int *)(rTIMEBase+0x48)) + #define rT4ISR (*(volatile int *)(rTIMEBase+0x4C)) + + #define rTTMR (*(volatile int *)(rTIMEBase+0x80)) + #define rTTIR (*(volatile int *)(rTIMEBase+0x84)) + #define rTTCR (*(volatile int *)(rTIMEBase+0x88)) + + + /* 7.RTC register(8bit)*/ + #define rRTCCON (*(volatile unsigned *)(rRTCBase+0x00)) /* RTC control register */ + #define rRTCRST (*(volatile unsigned *)(rRTCBase+0x04)) /* RTC round reset register */ + #define rRTCALM (*(volatile unsigned *)(rRTCBase+0x08)) /* RTC alarm register */ + #define rALMSEC (*(volatile unsigned *)(rRTCBase+0x0C)) /* Alarm second data register */ + #define rALMMIN (*(volatile unsigned *)(rRTCBase+0x10)) + #define rALMHOUR (*(volatile unsigned *)(rRTCBase+0x14)) /* Alarm hour data register */ + #define rALMDATE (*(volatile unsigned *)(rRTCBase+0x18)) /* Alarm date data register */ + #define rALMDAY (*(volatile unsigned *)(rRTCBase+0x1C)) /* Alarm day data register */ + #define rALMMON (*(volatile unsigned *)(rRTCBase+0x20)) /* Alarm mon data register */ + #define rALMYEAR (*(volatile unsigned *)(rRTCBase+0x24)) /* Alarm year data register */ + #define rBCDSEC (*(volatile unsigned *)(rRTCBase+0x28)) /* BCD second data register */ + #define rBCDMIN (*(volatile unsigned *)(rRTCBase+0x2C)) /* BCD minute data register */ + #define rBCDHOUR (*(volatile unsigned *)(rRTCBase+0x30)) /* BCD hour data register */ + #define rBCDDATE (*(volatile unsigned *)(rRTCBase+0x34)) /* BCD day data register */ + #define rBCDDAY (*(volatile unsigned *)(rRTCBase+0x38)) /* BCD day data register */ + #define rBCDMON (*(volatile unsigned *)(rRTCBase+0x3C)) /* BCD month data register */ + #define rBCDYEAR (*(volatile unsigned *)(rRTCBase+0x40)) /* BCD year data register */ + #define rRTCIM (*(volatile unsigned *)(rRTCBase+0x44)) /* BCD year data register */ + #define rRTCPEND (*(volatile unsigned *)(rRTCBase+0x48)) /* BCD year data register */ + + + /* 8.Watch Dog Timer register(8bit)*/ + + /* 9.Programmable I/O port */ + #define rGIOPCON (*(volatile unsigned *)(rIOPBase+0x00)) /* Port direction register */ + #define rGIOPDATA (*(volatile unsigned *)(rIOPBase+0x04)) /* Data register */ + #define rGIOPINTEN (*(volatile unsigned *)(rIOPBase+0x08)) /* Interrupt enable register */ + #define rGIOPLEVEL (*(volatile unsigned *)(rIOPBase+0x0C)) /* Ative level indication register */ + #define rGIOPPEND (*(volatile unsigned *)(rIOPBase+0x10)) /* Interrupt pending register */ + + + /* 10.Interrupt controller */ //0xc082800 + #define rINTCON (*(volatile unsigned *)(rINTBase+0x00)) /* interrupt control register */ + #define rINTPND (*(volatile unsigned *)(rINTBase+0x04)) /* interrupt pending register */ + #define rINTMOD (*(volatile unsigned *)(rINTBase+0x08)) /* interrupt mode register */ + #define rINTMSK (*(volatile unsigned *)(rINTBase+0x0C)) /* interrupt mask register */ + #define rINTLEVEL (*(volatile unsigned *)(rINTBase+0x10)) + #define rIRQPSLV0 (*(volatile unsigned *)(rINTBase+0x14)) /* IRQ priority of slave register0 */ + #define rIRQPSLV1 (*(volatile unsigned *)(rINTBase+0x18)) /* IRQ priority of slave register1 */ + #define rIRQPSLV2 (*(volatile unsigned *)(rINTBase+0x1C)) /* IRQ priority of slave register2 */ + #define rIRQPSLV3 (*(volatile unsigned *)(rINTBase+0x20)) /* IRQ priority of slave register3 */ + #define rIRQPMST (*(volatile unsigned *)(rINTBase+0x24)) /* IRQ priority of master register */ + #define rIRQCSLV0 (*(volatile unsigned *)(rINTBase+0x28)) /* current IRQ priority of slave register0 */ + #define rIRQCSLV1 (*(volatile unsigned *)(rINTBase+0x2C)) /* current IRQ priority of slave register1 */ + #define rIRQCSLV2 (*(volatile unsigned *)(rINTBase+0x30)) /* current IRQ priority of slave register2 */ + #define rIRQCSLV3 (*(volatile unsigned *)(rINTBase+0x34)) /* current IRQ priority of slave register3 */ + #define rIRQCMST (*(volatile unsigned *)(rINTBase+0x38)) /* current IRQ priority of master register */ + #define rIRQISPR (*(volatile unsigned *)(rINTBase+0x3C)) /* IRQ service pending register */ + #define rIRQISPC (*(volatile unsigned *)(rINTBase+0x40)) /* IRQ service clear register */ + #define rFIQPSLV0 (*(volatile unsigned *)(rINTBase+0x44)) /* FIQ priority of slave register0 */ + #define rFIQPSLV1 (*(volatile unsigned *)(rINTBase+0x48)) /* FIQ priority of slave register1 */ + #define rFIQPSLV2 (*(volatile unsigned *)(rINTBase+0x4C)) /* FIQ priority of slave register2 */ + #define rFIQPSLV3 (*(volatile unsigned *)(rINTBase+0x50)) /* FIQ priority of slave register3 */ + #define rFIQPMST (*(volatile unsigned *)(rINTBase+0x54)) /* FIQ priority of master register */ + #define rFIQCSLV0 (*(volatile unsigned *)(rINTBase+0x58)) /* current FIQ priority of slave register0 */ + #define rFIQCSLV1 (*(volatile unsigned *)(rINTBase+0x5C)) /* current FIQ priority of slave register1 */ + #define rFIQCSLV2 (*(volatile unsigned *)(rINTBase+0x60)) /* current FIQ priority of slave register2 */ + #define rFIQCSLV3 (*(volatile unsigned *)(rINTBase+0x64)) /* current FIQ priority of slave register3 */ + #define rFIQCMST (*(volatile unsigned *)(rINTBase+0x68)) /* current FIQ priority of master register */ + #define rFIQISPR (*(volatile unsigned *)(rINTBase+0x6C)) /* FIQ service pending register */ + #define rFIQISPC (*(volatile unsigned *)(rINTBase+0x70)) /* FIQ service clear register */ + #define rPOLARITY (*(volatile unsigned *)(rINTBase+0x74)) + #define rIVEC_ADDR (*(volatile unsigned *)(rINTBase+0x78)) + #define rFVEC_ADDR (*(volatile unsigned *)(rINTBase+0x7C)) + + /* 11.SSP(prime cell) Synchronous serial port register(16bit) */ + + + /* 12.KMI0(prime cell) Keyboard/Mouse interface register(8bit) */ + + /* 13.KMI1(prime cell) Keyboard/Mouse interface register(8bit) */ + + + /* 14.UART0(prime cell) register(8bit)*/ + + + /* 15.UART1(prime cell) register(8bit)*/ + + + /* 16.Power manager register */ + #define rPLLCON (*(volatile unsigned *)(rPMBase+0x00)) /* pll configuration register */ + #define rMODCON (*(volatile unsigned *)(rPMBase+0x04)) /* mode control register */ + #define rLOCKCON (*(volatile unsigned *)(rPMBase+0x08)) /* Lock-up timer */ + #define rHCLKCON (*(volatile unsigned *)(rPMBase+0x0C)) /* Normal system clock control register */ + + + /* 17.Teak base register */ + + //- timer register + /* + * Bits Name Type Function + * 15:12 - Read Reserved. Read only as zero + * 11:10 M Read/write Operating mode : + * 00 : Free running timer mode(default) 01 : Periodic timer mode. + * 10 : Free running counter mode. 11 : Periodic counter mode. + * 9:8 ES Read/write External input active edge selection. + * 00 : Positive edge(default). 01 : Negative edge. + * 10 : Both positive and negative edge. 11 : unused. + * 7 - Read Reserved. Read only as zero + * 6 OM Read/write Time output mode. 0 : Toggle mode(default). 1 : Pulse mode. + * 5 UDS Read/write Up/down counting control selection. + * 0 : Up/down is controlled by UD field of TxCTR register(default). + * 1 : Up/down is controlled by EXTUD[4:0]input register. + * 4 UD Read/write Up/down counting selection. + * 0 : Down counting(default). 1 : Up counting. + * This bit affects the counting of timer only when UDS bit is LOW. + * 3 - Read Reserved. Read only as zero + * 2 OE Read/write Output enable. + * 0 : Disable timer outputs(default). 1 : Enable timer outputs. + * This bit affects the generation of timer interrupt only when TE bit is HIGH. + * 1 IE Read/write Interrupt enable. 0 : Toggle mode(default). 1 : Pulse mode. + * This bit affects the generation of timer output only when TE bit is HIGH. + * 0 TE Read/write Timer enable. 0 : Diable timer(default). 1 : Enable timer. + */ + #define TMR_TE_DISABLE 0x0000 + #define TMR_TE_ENABLE 0x0001 + + #define TMR_IE_TOGGLE 0x0000 + #define TMR_IE_PULSE 0x0002 + + #define TMR_OE_DISABLE 0x0000 + #define TMR_OE_ENABLE 0x0004 + + #define TMR_UD_DOWN 0x0000 + #define TMR_UD_UP 0x0010 + + #define TMR_UDS_TxCTR 0x0000 + #define TMR_UDS_EXTUD 0x0020 + + #define TMR_OM_TOGGLE 0x0000 + #define TMR_OM_PULSE 0x0040 + + #define TMR_ES_POS 0x0000 + #define TMR_ES_NEG 0x0100 + #define TMR_ES_BOTH 0x0200 + + #define TMR_M_FREE_TIMER 0x0000 + #define TMR_M_PERIODIC_TIMER 0x0400 + #define TMR_M_FREE_COUNTER 0x0800 + #define TMR_M_PERIODIC_COUNTER 0x0C00 + + + /* 18.memory stick Host controller-External Device 1*/ + #define COMD_REG (*(volatile unsigned short *)(rEXT1Base+0x0)) /* Command Register */ + #define STAT_REG (*(volatile unsigned short *)(rEXT1Base+0x4)) /* Status Register */ + #define CONT_REG (*(volatile unsigned short *)(rEXT1Base+0x4)) /* Control Register */ + #define RECV_REG (*(volatile unsigned short *)(rEXT1Base+0x8)) /* Receive Data Register */ + #define SEND_REG (*(volatile unsigned short *)(rEXT1Base+0x8)) /* Send Data Register */ + #define INTD_REG (*(volatile unsigned short *)(rEXT1Base+0xc)) /* Interrupt Data Register */ + #define INTC_REG (*(volatile unsigned short *)(rEXT1Base+0xc)) /* Interrupt Control Register */ + #define PARD_REG (*(volatile unsigned short *)(rEXT1Base+0x10)) /* Parallel Data Register */ + #define PARC_REG (*(volatile unsigned short *)(rEXT1Base+0x10)) /* Parallel Control Register */ + #define CONT2_REG (*(volatile unsigned short *)(rEXT1Base+0x14)) + #define ACD_REG (*(volatile unsigned short *)(rEXT1Base+0x18)) + + + /* Searching Keyword: OS_Timer */ + #define SYS_TIMER03_PRESCALER 0x6B /* for System Timer, 4usec(3.996) */ + #define SYS_TIMER03_DIVIDER 0x01 + + #define RESCHED_PERIOD 10 /* 10 ms */ + #define __KERNEL_HZ 100 + +#endif /* __S5C7375_H */ diff --git a/include/asm-arm/arch-s5c7375/system.h b/include/asm-arm/arch-s5c7375/system.h new file mode 100644 index 00000000..a8babe32 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/system.h @@ -0,0 +1,63 @@ +/* + * linux/include/asm-arm/arch-s5c7375/system.h + * + * Copyright (C) 2002 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include + +/* + * This functions used in arm/kernel/process.c + */ + +#ifdef CONFIG_LEDS +extern void Led_Display(int); +#endif + +static void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ +#ifndef CONFIG_LEDS + cpu_do_idle(); +#else + int i; + Led_Display(1); + rCLKCON |= (1<<2); /* Enter IDLE Mode */ + for ( i = 0; i <100;i++); + rCLKCON &= ~(1<<2); + Led_Display(4); +#endif + +} + +static inline void arch_reset(char mode) +{ + /* machine should reboot..... */ + mdelay(5000); + panic("Watchdog timer reset failed!\n"); + printk(" Jump to address 0 \n"); + cpu_reset(0); +} + +#endif diff --git a/include/asm-arm/arch-s5c7375/time.h b/include/asm-arm/arch-s5c7375/time.h new file mode 100644 index 00000000..38a6ba2a --- /dev/null +++ b/include/asm-arm/arch-s5c7375/time.h @@ -0,0 +1,88 @@ +/* + * linux/include/asm-arm/arch-s5c7375/time.h + * + * Copyright (C) SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 +#include +#include +/* + * Bits Name Type Function + * 15:12 - Read Reserved. Read only as zero + * 11:10 M Read/write Operating mode : + * 00 : Free running timer mode(default) 01 : Periodic timer mode. + * 10 : Free running counter mode. 11 : Periodic counter mode. + * 9:8 ES Read/write External input active edge selection. + * 00 : Positive edge(default). 01 : Negative edge. + * 10 : Both positive and negative edge. 11 : unused. + * 7 - Read Reserved. Read only as zero + * 6 OM Read/write Time output mode. 0 : Toggle mode(default). 1 : Pulse mode. + * 5 UDS Read/write Up/down counting control selection. + * 0 : Up/down is controlled by UD field of TxCTR register(default). + * 1 : Up/down is controlled by EXTUD[4:0]input register. + * 4 UD Read/write Up/down counting selection. + * 0 : Down counting(default). 1 : Up counting. + * This bit affects the counting of timer only when UDS bit is LOW. + * 3 - Read Reserved. Read only as zero + * 2 OE Read/write Output enable. + * 0 : Disable timer outputs(default). 1 : Enable timer outputs. + * This bit affects the generation of timer interrupt only when TE bit is HIGH. + * 1 IE Read/write Interrupt enable. 0 : Toggle mode(default). 1 : Pulse mode. + * This bit affects the generation of timer output only when TE bit is HIGH. + * 0 TE Read/write Timer enable. 0 : Diable timer(default). 1 : Enable timer. + */ + +#define TMR_TE_DISABLE 0x0000 +#define TMR_TE_ENABLE 0x0001 + +#define TMR_IE_TOGGLE 0x0000 +#define TMR_IE_PULSE 0x0002 + +#define TMR_OE_DISABLE 0x0000 +#define TMR_OE_ENABLE 0x0004 + +#define TMR_UD_DOWN 0x0000 +#define TMR_UD_UP 0x0010 + +#define TMR_UDS_TxCTR 0x0000 +#define TMR_UDS_EXTUD 0x0020 + +#define TMR_OM_TOGGLE 0x0000 +#define TMR_OM_PULSE 0x0040 + +#define TMR_ES_POS 0x0000 +#define TMR_ES_NEG 0x0100 +#define TMR_ES_BOTH 0x0200 + +#define TMR_M_FREE_TIMER 0x0000 +#define TMR_M_PERIODIC_TIMER 0x0400 +#define TMR_M_FREE_COUNTER 0x0800 +#define TMR_M_PERIODIC_COUNTER 0x0C00 + + + + +/* + * simpler new version of gettimeoffset + * by Hyok S. Choi + */ +#define TICKS_PER_uSEC 24 +#define CLOCKS_PER_USEC (2* ECLK/ (SYS_TIMER03_PRESCALER +1)) + //(ECLK/1000000) /* (ARM_CLK/1000000) */ + /* this is the newer version */ + diff --git a/include/asm-arm/arch-s5c7375/timex.h b/include/asm-arm/arch-s5c7375/timex.h new file mode 100644 index 00000000..86bc9e7e --- /dev/null +++ b/include/asm-arm/arch-s5c7375/timex.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-s5c7375/timex.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + +#define CLOCK_TICK_RATE (ECLK/ (SYS_TIMER03_PRESCALER +1)) + + /* + * 27M / (0x6B +1) = 4usec + */ diff --git a/include/asm-arm/arch-s5c7375/uncompress.h b/include/asm-arm/arch-s5c7375/uncompress.h new file mode 100644 index 00000000..e5960b93 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/uncompress.h @@ -0,0 +1,58 @@ +/* + * linux/include/asm-armnommu/arch-s5c7375/uncompress.h + * + * Copyright (C) 2004 Hyok S. Choi, Samsung Electronics Co.,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 + */ +#include + +#ifndef __UNCOMPRESS_H__ +#define __UNCOMPRESS_H__ + +/* + * just use DCC JTAG1 port + */ +static inline void puts(const char *s) +{ + dcc_puts(s); +} + +static void puts_hex(unsigned long i) +{ + char lhex_buf[]="0x00000000"; + unsigned long ii,v; + + for(ii=9;ii>1;ii--) + { + v=(((0x0000000F << ((9-ii)*4)) & i) >> ((9-ii)*4)); + if(v>9) + lhex_buf[ii]=(char)('A'+v-10); + else + lhex_buf[ii]=(char)('0'+v); + } + + dcc_puts(lhex_buf); +} + + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif diff --git a/include/asm-arm/arch-s5c7375/vmalloc.h b/include/asm-arm/arch-s5c7375/vmalloc.h new file mode 100644 index 00000000..75ab6229 --- /dev/null +++ b/include/asm-arm/arch-s5c7375/vmalloc.h @@ -0,0 +1,35 @@ +/* + * linux/include/asm-armnommu/arch-s5c7375/vmalloc.h + * + * Copyright (C) 2003 SAMSUNG ELECTRONICS + * Hyok S. Choi + * + * 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 + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define MAX_S5C7375_SDRAM_SIZE (0x10000000) + +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + MAX_S5C7375_SDRAM_SIZE) diff --git a/include/asm-arm/byteorder.h b/include/asm-arm/byteorder.h index e6f7fcdc..6239340e 100644 --- a/include/asm-arm/byteorder.h +++ b/include/asm-arm/byteorder.h @@ -11,6 +11,8 @@ * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7 * and word accesses (data or instruction) appear as: * d0...d31 + * + * modified for some compatibility trouble with 2.9x GCC by Hyok S. Choi */ #ifndef __ASM_ARM_BYTEORDER_H #define __ASM_ARM_BYTEORDER_H @@ -48,6 +50,12 @@ static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) # define __SWAB_64_THRU_32__ #endif +#if !defined(__KERNEL__) +# ifndef __attribute_const__ +# define __attribute_const__ /* unimplemented */ +# endif +#endif + #ifdef __ARMEB__ #include #else diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index f0845646..b2bf1ee4 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -41,6 +41,22 @@ # endif #endif +#if defined(CONFIG_CPU_ARM7TDMI) || defined(CONFIG_CPU_ARM9TDMI) +# ifdef _CACHE +# define MULTI_CACHE 1 +# else +# define _CACHE v4 +# endif +#endif + +#if defined(CONFIG_CPU_S3C4510B) +# ifdef _CACHE +# define MULTI_CACHE 1 +# else +# define _CACHE s3c4510b +# endif +#endif + #if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \ defined(CONFIG_CPU_ARM925T) || defined(CONFIG_CPU_ARM1020) # define MULTI_CACHE 1 diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h index 4679f636..1e30e291 100644 --- a/include/asm-arm/cpu-multi32.h +++ b/include/asm-arm/cpu-multi32.h @@ -2,6 +2,7 @@ * linux/include/asm-arm/cpu-multi32.h * * Copyright (C) 2000 Russell King + * Modified by Hyok S. Choi, 2004 * * 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 @@ -49,10 +50,12 @@ extern struct processor { * Set the page table */ void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm); +#ifdef CONFIG_MMU /* * Set a PTE */ void (*set_pte)(pte_t *ptep, pte_t pte); +#endif } processor; #define cpu_proc_init() processor._proc_init() @@ -60,5 +63,7 @@ extern struct processor { #define cpu_reset(addr) processor.reset(addr) #define cpu_do_idle() processor._do_idle() #define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) +#ifdef CONFIG_MMU #define cpu_set_pte(ptep, pte) processor.set_pte(ptep, pte) +#endif #define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h index 6723e672..9d507434 100644 --- a/include/asm-arm/cpu-single.h +++ b/include/asm-arm/cpu-single.h @@ -2,6 +2,7 @@ * linux/include/asm-arm/cpu-single.h * * Copyright (C) 2000 Russell King + * Modified by Hyok S. Choi, 2004 * * 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 @@ -28,7 +29,9 @@ #define cpu_do_idle __cpu_fn(CPU_NAME,_do_idle) #define cpu_dcache_clean_area __cpu_fn(CPU_NAME,_dcache_clean_area) #define cpu_do_switch_mm __cpu_fn(CPU_NAME,_switch_mm) +#ifdef CONFIG_MMU #define cpu_set_pte __cpu_fn(CPU_NAME,_set_pte) +#endif #include @@ -40,5 +43,7 @@ extern void cpu_proc_fin(void); extern int cpu_do_idle(void); extern void cpu_dcache_clean_area(void *, int); extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); +#ifdef CONFIG_MMU extern void cpu_set_pte(pte_t *ptep, pte_t pte); +#endif extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); diff --git a/include/asm-arm/fast_timer.h b/include/asm-arm/fast_timer.h new file mode 100644 index 00000000..1578aa2f --- /dev/null +++ b/include/asm-arm/fast_timer.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-arm/flat.h b/include/asm-arm/flat.h index 96694647..f42d0171 100644 --- a/include/asm-arm/flat.h +++ b/include/asm-arm/flat.h @@ -1,16 +1,20 @@ /* - * include/asm-arm/flat.h -- uClinux flat-format executables + * include/asm-armnommu/flat.h -- uClinux flat-format executables + * + * Copyright (C) 2003, Hyok S. Choi + * */ -#ifndef __ARM_FLAT_H__ -#define __ARM_FLAT_H__ +#ifndef __ARMNOMMU_FLAT_H__ +#define __ARMNOMMU_FLAT_H__ #define flat_stack_align(sp) /* nothing needed */ #define flat_argvp_envp_on_stack() 1 #define flat_old_ram_flag(flags) (flags) #define flat_reloc_valid(reloc, size) ((reloc) <= (size)) -#define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp) +#define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp) #define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp) #define flat_get_relocate_addr(rel) (rel) -#endif /* __ARM_FLAT_H__ */ +#endif /* __ARMNOMMU_FLAT_H__ */ + diff --git a/include/asm-arm/glue.h b/include/asm-arm/glue.h index 0cc5d3b1..8210e015 100644 --- a/include/asm-arm/glue.h +++ b/include/asm-arm/glue.h @@ -50,6 +50,14 @@ # endif #endif +#if defined(CONFIG_CPU_S3C4510B) +# ifdef CPU_ABORT_HANDLER +# define MULTI_ABORT 1 +# else +# define CPU_ABORT_HANDLER cpu_s3c4510b_data_abort +# endif +#endif + #if defined(CONFIG_CPU_ARM710) # ifdef CPU_ABORT_HANDLER # define MULTI_ABORT 1 @@ -74,6 +82,14 @@ # endif #endif +#ifdef CONFIG_CPU_ABRT_NOMMU +# ifdef CPU_ABORT_HANDLER +# define MULTI_ABORT 1 +# else +# define CPU_ABORT_HANDLER nommu_early_abort +# endif +#endif + #ifdef CONFIG_CPU_ABRT_EV4T # ifdef CPU_ABORT_HANDLER # define MULTI_ABORT 1 diff --git a/include/asm-arm/hardware.h b/include/asm-arm/hardware.h index 1fd1a5b6..d3067b6d 100644 --- a/include/asm-arm/hardware.h +++ b/include/asm-arm/hardware.h @@ -2,6 +2,7 @@ * linux/include/asm-arm/hardware.h * * Copyright (C) 1996 Russell King + * Copyright (C) 2004 Hyok S. Choi * * 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 @@ -15,4 +16,26 @@ #include +#ifndef CONFIG_MMU + +#ifndef __ASSEMBLY__ + +/* the machine dependent bootmem reserve and free routines */ +#ifndef MACH_RESERVE_BOOTMEM +#define MACH_RESERVE_BOOTMEM() +#endif + +#ifndef MACH_FREE_BOOTMEM +#define MACH_FREE_BOOTMEM() +#endif + +/* by default, initmem is freed */ +#ifndef DO_FREE_INITMEM +#define DO_FREE_INITMEM() (1) +#endif + +#endif /* !__ASSEMBLY__ */ + +#endif /* !CONFIG_MMU */ + #endif diff --git a/include/asm-arm/hardware/dcc.h b/include/asm-arm/hardware/dcc.h new file mode 100644 index 00000000..fd465f89 --- /dev/null +++ b/include/asm-arm/hardware/dcc.h @@ -0,0 +1,49 @@ +/* + * linux/include/asm-armnommu/hardware/dcc.h + * + * Copyright (C) 2004 Hyok S. Choi, Samsung Electronics Co.,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 + */ +#ifndef __DCC_PUTS__ +#define __DCC_PUTS__ +static void dcc_puts(const char *p) +{ +#ifndef CONFIG_JTAG_DCC_OUTPUT_DISABLE + /* + r0 = string ; string address + r1 = 2 ; state check bit (write) + r4 = *string ; character + */ + __asm__ __volatile__( + " ldrb r4, [%0] @ load a char\n" + "1: mrc p14, 0, r3, c0, c0 @ read comms control reg\n" + " and r3, r3, #2 @ the write buffer status\n" + " cmp r3, #2 @ is it available?\n" + " beq 1b @ is not, wait till then\n" + " mcr p14, 0, r4, c1, c0 @ write it\n" + " cmp r4, #0x0a @ is it LF?\n" + " bne 2f @ if it is not, continue\n" + " mov r4, #0x0d @ set the CR\n" + " b 1b @ loop for writing CR\n" + "2: ldrb r4, [%0, #1]! @ load a char\n" + " cmp r4, #0x0 @ test is null\n" + " bne 1b @ if it is not yet, loop" + : /* no output register */ + : "r" (p) + : "r3", "r4"); +#endif +} +#endif diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index fd2f9bf4..7fbb7246 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -2,6 +2,7 @@ * linux/include/asm-arm/mach/arch.h * * Copyright (C) 2000 Russell King + * Modified by Hyok S. Choi for uClinux, 2004 * * 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 diff --git a/include/asm-arm/mach/i2c-gpio.h b/include/asm-arm/mach/i2c-gpio.h new file mode 100644 index 00000000..8a47ec45 --- /dev/null +++ b/include/asm-arm/mach/i2c-gpio.h @@ -0,0 +1,24 @@ +/* + * include/asm-arm/mach/i2c-gpio.h + * + * Several platforms use GPIO pins to implement bit-bang I2C + * controllers. This file defines a structure that can be passed + * via the device model to provide the gpio pins to the I2C drivers. + * + * Author: Deepak Saxena + * + * Copyright 2003-2004 (c) 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. + */ +#ifndef ASMARM_MACH_I2C_GPIO_H +#define ASMARM_MACH_I2C_GPIO_H + +struct i2c_gpio_pins { + unsigned long sda_pin; + unsigned long scl_pin; +}; + +#endif diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h index d1a65b1e..5d986d9c 100644 --- a/include/asm-arm/mmu_context.h +++ b/include/asm-arm/mmu_context.h @@ -13,6 +13,9 @@ #ifndef __ASM_ARM_MMU_CONTEXT_H #define __ASM_ARM_MMU_CONTEXT_H +#ifndef CONFIG_MMU +#include "nommu_context.h" +#else /* !CONFIG_MMU */ #include #include #include @@ -108,4 +111,5 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev,next) switch_mm(prev, next, NULL) +#endif /* CONFIG_MMU */ #endif diff --git a/include/asm-arm/nommu.h b/include/asm-arm/nommu.h new file mode 100644 index 00000000..5073cdf1 --- /dev/null +++ b/include/asm-arm/nommu.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/nommu.h + * + * Copyright (C) 2002, David McCullough + * modified for 2.6 by Hyok S. Choi + */ + +#ifndef __ARM_NOMMU_H +#define __ARM_NOMMU_H + +typedef struct { + struct vm_list_struct *vmlist; + unsigned long end_brk; +} mm_context_t; + +#endif diff --git a/include/asm-arm/nommu_context.h b/include/asm-arm/nommu_context.h new file mode 100644 index 00000000..ad31d474 --- /dev/null +++ b/include/asm-arm/nommu_context.h @@ -0,0 +1,45 @@ +/* + * linux/include/asm-arm/nommu_context.h + * + * Copyright (C) 2001 RidgRun Inc (www.ridgerun.com) + * Copyright (C) 2004 Hyok S. Choi + * + * 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. + * + * Changelog: + * 20-02-2001 GJM Gutted for uClinux + * 05-03-2004 HSC modified for 2.6 + */ +#ifndef __ASM_ARM_NOMMU_CONTEXT_H +#define __ASM_ARM_NOMMU_CONTEXT_H + +#include +#include +#include + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +extern inline int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + return(0); +} + +#define destroy_context(mm) do { } while(0) + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) +{ +} + +#define deactivate_mm(tsk,mm) do { } while (0) + +extern inline void activate_mm(struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ +} + +#endif diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h index ea7e54c3..2ae0a990 100644 --- a/include/asm-arm/proc-fns.h +++ b/include/asm-arm/proc-fns.h @@ -209,6 +209,7 @@ #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) +#ifdef CONFIG_MMU #define cpu_get_pgd() \ ({ \ unsigned long pg; \ @@ -217,6 +218,7 @@ pg &= ~0x3fff; \ (pgd_t *)phys_to_virt(pg); \ }) +#endif #endif diff --git a/include/asm-arm/procinfo.h b/include/asm-arm/procinfo.h index 91a31adf..383cd277 100644 --- a/include/asm-arm/procinfo.h +++ b/include/asm-arm/procinfo.h @@ -2,6 +2,7 @@ * linux/include/asm-arm/procinfo.h * * Copyright (C) 1996-1999 Russell King + * Modified by Hyok S. Choi, 2004 * * 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 @@ -12,8 +13,10 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_MMU struct cpu_tlb_fns; struct cpu_user_fns; +#endif struct cpu_cache_fns; struct processor; diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h index 5a8ef787..25ac406b 100644 --- a/include/asm-arm/ptrace.h +++ b/include/asm-arm/ptrace.h @@ -150,6 +150,8 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define profile_pc(regs) instruction_pointer(regs) #endif +#define user_stack(regs) ((regs)->ARM_sp) + #ifdef __KERNEL__ #define predicate(x) ((x) & 0xf0000000) #define PREDICATE_ALWAYS 0xe0000000 diff --git a/include/asm-arm/string.h b/include/asm-arm/string.h index e50c4a39..82373dca 100644 --- a/include/asm-arm/string.h +++ b/include/asm-arm/string.h @@ -13,7 +13,9 @@ extern char * strrchr(const char * s, int c); extern char * strchr(const char * s, int c); #define __HAVE_ARCH_MEMCPY +#if 0 // mask by Victor Yu. 02-12-2007 extern void * memcpy(void *, const void *, __kernel_size_t); +#endif #define __HAVE_ARCH_MEMMOVE extern void * memmove(void *, const void *, __kernel_size_t); @@ -23,7 +25,9 @@ extern void * memchr(const void *, int, __kernel_size_t); #define __HAVE_ARCH_MEMZERO #define __HAVE_ARCH_MEMSET +#if 0 // mask by Victor Yu. 02-12-2007 extern void * memset(void *, int, __kernel_size_t); +#endif extern void __memzero(void *ptr, __kernel_size_t n); diff --git a/include/asm-arm/uaccess-nommu.h b/include/asm-arm/uaccess-nommu.h new file mode 100644 index 00000000..3cab9f08 --- /dev/null +++ b/include/asm-arm/uaccess-nommu.h @@ -0,0 +1,203 @@ +/* + * linux/include/asm-arm/uaccess-nommu.h + * + * Copyright (C) 2003 Hyok S. Choi, Samsung Electronics Co.,Ltd. + + * 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. + */ +#ifndef _ASMARM_UACCESS_NOMMU_H +#define _ASMARM_UACCESS_NOMMU_H + +/* + * Note that this is actually 0x1,0000,0000 + */ +#define KERNEL_DS 0x00000000 +/* uClinux has only one addr space. */ +#define USER_DS KERNEL_DS + +#define get_ds() (KERNEL_DS) +#define get_fs() (USER_DS) + +static inline void set_fs (mm_segment_t fs) +{ /* nothing to do here for uClinux */ +} + +/* segment always equal. */ +#define segment_eq(a,b) 1 + +/* + * assuming __range_ok & __addr_ok always succeed. + */ +#define __addr_ok(addr) 1 +#define __range_ok(addr,size) 0 + +#define access_ok(type,addr,size) 1 + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + */ + +#define get_user(x, p) \ + ({ \ + int __e = 0; \ + unsigned long __gu_val; \ + switch (sizeof(*(p))) { \ + case 1: \ + __get_user_asm_byte(__gu_val, p, __e); \ + break; \ + case 2: \ + __get_user_asm_half(__gu_val, p, __e); \ + break; \ + case 4: \ + __get_user_asm_word(__gu_val, p, __e); \ + break; \ + default: __e = __get_user_bad(); break; \ + } \ + (x) = (typeof(*(p)))__gu_val; \ + __e; \ + }) + +#define __get_user(x, ptr) get_user(x, ptr) +#define __get_user_error(x,ptr,err) get_user(x, ptr) + +#define __get_user_asm_byte(x,addr,err) \ + __asm__ __volatile__( \ + "ldrbt %0,[%1],#0" \ + : "=&r" (x) \ + : "r" (addr) \ + : "cc") + +#ifndef __ARMEB__ +#define __get_user_asm_half(x,__gu_addr,err) \ +({ \ + unsigned long __b1, __b2; \ + __get_user_asm_byte(__b1, __gu_addr, err); \ + __get_user_asm_byte(__b2, __gu_addr + 1, err); \ + (x) = __b1 | (__b2 << 8); \ +}) +#else +#define __get_user_asm_half(x,__gu_addr,err) \ +({ \ + unsigned long __b1, __b2; \ + __get_user_asm_byte(__b1, __gu_addr, err); \ + __get_user_asm_byte(__b2, __gu_addr + 1, err); \ + (x) = (__b1 << 8) | __b2; \ +}) +#endif + +#define __get_user_asm_word(x,addr,err) \ + __asm__ __volatile__( \ + "ldrt %0,[%1],#0\n" \ + : "=&r" (x) \ + : "r" (addr) \ + : "cc") + +extern int __get_user_bad(void); + + +#define put_user(x, p) \ + ({ \ + int __e = 0; \ + typeof(*(p)) __pu_val = (x); \ + typeof(*(p)) __user *__p = (p);\ + switch (sizeof(*(p))) { \ + case 1: \ + __put_user_asm_byte(__pu_val, __p, __e);\ + break; \ + case 2: \ + __put_user_asm_half(__pu_val, __p, __e);\ + break; \ + case 4: \ + __put_user_asm_word(__pu_val, __p, __e);\ + break; \ + case 8: \ + __put_user_asm_dword(__pu_val, __p, __e);\ + break; \ + default: __e = __put_user_bad(); break; \ + } \ + __e; \ + }) + +#define __put_user(x, ptr) put_user(x, ptr) +#define __put_user_error(x,ptr,err) put_user(x, ptr) + +#define __put_user_asm_byte(x,__pu_addr,err) \ + __asm__ __volatile__( \ + "strbt %0,[%1],#0\n" \ + : /* none */ \ + : "r" (x), "r" (__pu_addr) \ + : "cc") + + +#ifndef __ARMEB__ +#define __put_user_asm_half(x,__pu_addr,err) \ +({ \ + unsigned long __temp = (unsigned long)(x); \ + __put_user_asm_byte(__temp, __pu_addr, err); \ + __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err); \ +}) +#else +#define __put_user_asm_half(x,__pu_addr,err) \ +({ \ + unsigned long __temp = (unsigned long)(x); \ + __put_user_asm_byte(__temp >> 8, __pu_addr, err); \ + __put_user_asm_byte(__temp, __pu_addr + 1, err); \ +}) +#endif + +#define __put_user_asm_word(x,__pu_addr,err) \ + __asm__ __volatile__( \ + "strt %0,[%1],#0" \ + : /* none */ \ + : "r" (x), "r" (__pu_addr) \ + : "cc") + +#ifndef __ARMEB__ +#define __reg_oper0 "%R1" +#define __reg_oper1 "%Q1" +#else +#define __reg_oper0 "%Q1" +#define __reg_oper1 "%R1" +#endif + +#define __put_user_asm_dword(x,__pu_addr,err) \ + __asm__ __volatile__( \ + "strt " __reg_oper1 ", [%0], #4\n" \ + "strt " __reg_oper0 ", [%0], #0" \ + : "+r" (__pu_addr) \ + : "r" (x) \ + : "cc") + +extern int __put_user_bad(void); + +#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) +#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) +#define clear_user(to, n) (memset(to, 0, n), 0) + +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __clear_user(ptr, n) clear_user(ptr, n) + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +/* these are just for symbol compatibility */ +static inline unsigned long __arch_copy_from_user (void *to, void *from, unsigned long n) +{ + return copy_from_user(to, from, n); +} + +static inline unsigned long __arch_copy_to_user (void *to, void *from, unsigned long n) +{ + return copy_to_user(to, from, n); +} + +static inline unsigned long __arch_clear_user(void *to, unsigned long n) +{ + return clear_user(to, n); +} + +#endif /* _ASMARM_UACCESS-NOMMU_H */ diff --git a/include/asm-arm/unaligned.h b/include/asm-arm/unaligned.h index 795b9e5b..ce574035 100644 --- a/include/asm-arm/unaligned.h +++ b/include/asm-arm/unaligned.h @@ -59,6 +59,7 @@ extern int __bug_unaligned_x(const void *ptr); ((unsigned long long)__get_unaligned_4_be(__p) << 32 | \ __get_unaligned_4_be((__p+4))) +#if 0 // mask by Victor Yu. 02-12-2007 #define __get_unaligned_le(ptr) \ ({ \ const __u8 *__p = (const __u8 *)(ptr); \ @@ -68,6 +69,27 @@ extern int __bug_unaligned_x(const void *ptr); __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_le(__p), \ (void)__bug_unaligned_x(__p))))); \ }) +#else +#define __get_unaligned_le(ptr) \ + ({ \ + __typeof__(*(ptr)) __v; \ + __u8 *__p = (__u8 *)(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __v = *(ptr); break; \ + case 2: __v = __get_unaligned_2_le(__p); break; \ + case 4: __v = __get_unaligned_4_le(__p); break; \ + case 8: { \ + unsigned int __v1, __v2; \ + __v2 = __get_unaligned_4_le((__p+4)); \ + __v1 = __get_unaligned_4_le(__p); \ + __v = ((unsigned long long)__v2 << 32 | __v1); \ + } \ + break; \ + default: __v = __bug_unaligned_x(__p); break; \ + } \ + __v; \ + }) +#endif #define __get_unaligned_be(ptr) \ ({ \ diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 14a87eec..601642b7 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -153,9 +153,15 @@ #define __NR_mprotect (__NR_SYSCALL_BASE+125) #define __NR_sigprocmask (__NR_SYSCALL_BASE+126) /* 127 was sys_create_module */ +#if 1 // add by Victor Yu. 02-13-2007 +#define __NR_create_module (__NR_SYSCALL_BASE+127) +#endif #define __NR_init_module (__NR_SYSCALL_BASE+128) #define __NR_delete_module (__NR_SYSCALL_BASE+129) /* 130 was sys_get_kernel_syms */ +#if 1 // add by Victor Yu. 02-13-2007 +#define __NR_get_kernel_syms (__NR_SYSCALL_BASE+130) +#endif #define __NR_quotactl (__NR_SYSCALL_BASE+131) #define __NR_getpgid (__NR_SYSCALL_BASE+132) #define __NR_fchdir (__NR_SYSCALL_BASE+133) diff --git a/include/asm-i386/edd.h b/include/asm-i386/edd.h new file mode 100644 index 00000000..5b4bfefb --- /dev/null +++ b/include/asm-i386/edd.h @@ -0,0 +1,177 @@ +/* + * linux/include/asm-i386/edd.h + * Copyright (C) 2002, 2003 Dell, Inc. + * by Matt Domsch + * + * structures and definitions for the int 13h, ax={41,48}h + * BIOS Enhanced Disk Drive Services + * This is based on the T13 group document D1572 Revision 0 (August 14 2002) + * available at http://www.t13.org/docs2002/d1572r0.pdf. It is + * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf + * + * In a nutshell, arch/i386/boot/setup.S populates a scratch table + * in the empty_zero_block that contains a list of BIOS-enumerated + * boot devices. + * In arch/i386/kernel/setup.c, this information is + * transferred into the edd structure, and in arch/i386/kernel/edd.c, that + * information is used to identify BIOS boot disk. The code in setup.S + * is very sensitive to the size of these structures. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * 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. + * + */ +#ifndef _ASM_I386_EDD_H +#define _ASM_I386_EDD_H + +#define EDDNR 0x1e9 /* addr of number of edd_info structs at EDDBUF + in empty_zero_block - treat this as 1 byte */ +#define EDDBUF 0x600 /* addr of edd_info structs in empty_zero_block */ +#define EDDMAXNR 6 /* number of edd_info structs starting at EDDBUF */ +#define EDDEXTSIZE 4 /* change these if you muck with the structures */ +#define EDDPARMSIZE 74 +#define CHECKEXTENSIONSPRESENT 0x41 +#define GETDEVICEPARAMETERS 0x48 +#define EDDMAGIC1 0x55AA +#define EDDMAGIC2 0xAA55 + +#define READ_SECTORS 0x02 +#define MBR_SIG_OFFSET 0x1B8 +#define DISK80_SIG_BUFFER 0x2cc + +#ifndef __ASSEMBLY__ + +#define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) +#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1) +#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2) +#define EDD_EXT_64BIT_EXTENSIONS (1 << 3) + +#define EDD_INFO_DMA_BOUNDRY_ERROR_TRANSPARENT (1 << 0) +#define EDD_INFO_GEOMETRY_VALID (1 << 1) +#define EDD_INFO_REMOVABLE (1 << 2) +#define EDD_INFO_WRITE_VERIFY (1 << 3) +#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION (1 << 4) +#define EDD_INFO_LOCKABLE (1 << 5) +#define EDD_INFO_NO_MEDIA_PRESENT (1 << 6) +#define EDD_INFO_USE_INT13_FN50 (1 << 7) + +struct edd_device_params { + u16 length; + u16 info_flags; + u32 num_default_cylinders; + u32 num_default_heads; + u32 sectors_per_track; + u64 number_of_sectors; + u16 bytes_per_sector; + u32 dpte_ptr; /* 0xFFFFFFFF for our purposes */ + u16 key; /* = 0xBEDD */ + u8 device_path_info_length; /* = 44 */ + u8 reserved2; + u16 reserved3; + u8 host_bus_type[4]; + u8 interface_type[8]; + union { + struct { + u16 base_address; + u16 reserved1; + u32 reserved2; + } __attribute__ ((packed)) isa; + struct { + u8 bus; + u8 slot; + u8 function; + u8 channel; + u32 reserved; + } __attribute__ ((packed)) pci; + /* pcix is same as pci */ + struct { + u64 reserved; + } __attribute__ ((packed)) ibnd; + struct { + u64 reserved; + } __attribute__ ((packed)) xprs; + struct { + u64 reserved; + } __attribute__ ((packed)) htpt; + struct { + u64 reserved; + } __attribute__ ((packed)) unknown; + } interface_path; + union { + struct { + u8 device; + u8 reserved1; + u16 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) ata; + struct { + u8 device; + u8 lun; + u8 reserved1; + u8 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) atapi; + struct { + u16 id; + u64 lun; + u16 reserved1; + u32 reserved2; + } __attribute__ ((packed)) scsi; + struct { + u64 serial_number; + u64 reserved; + } __attribute__ ((packed)) usb; + struct { + u64 eui; + u64 reserved; + } __attribute__ ((packed)) i1394; + struct { + u64 wwid; + u64 lun; + } __attribute__ ((packed)) fibre; + struct { + u64 identity_tag; + u64 reserved; + } __attribute__ ((packed)) i2o; + struct { + u32 array_number; + u32 reserved1; + u64 reserved2; + } __attribute((packed)) raid; + struct { + u8 device; + u8 reserved1; + u16 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) sata; + struct { + u64 reserved1; + u64 reserved2; + } __attribute__ ((packed)) unknown; + } device_path; + u8 reserved4; + u8 checksum; +} __attribute__ ((packed)); + +struct edd_info { + u8 device; + u8 version; + u16 interface_support; + struct edd_device_params params; +} __attribute__ ((packed)); + +extern struct edd_info edd[EDDMAXNR]; +extern unsigned char eddnr; +extern unsigned int edd_disk80_sig; +#endif /*!__ASSEMBLY__ */ + +#endif /* _ASM_I386_EDD_H */ diff --git a/include/asm-m68knommu/DS1305RTC.h b/include/asm-m68knommu/DS1305RTC.h new file mode 100644 index 00000000..d20be226 --- /dev/null +++ b/include/asm-m68knommu/DS1305RTC.h @@ -0,0 +1,82 @@ +/*************************************************************************** + DS1305RTC.h - + Real time clock control functions . + These functions rely on the SPI module for communication. + ------------------- + begin : Tue Oct 14 2003 + email : ngustavson@emacinc.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. + * + ***************************************************************************/ +#ifndef DS1305RTC_H +#define DS1305RTC_H +#include +#include +#include + + +#define WRITE_OFFSET 0x80 +enum registers { SEC,MIN,HOURS,DAY,DATE,MONTH,YEAR, +SEC_ALARM0,MIN_ALARM0,HOUR_ALARM0,DAY_ALARM0, //alarm0 +SEC_ALARM1,MIN_ALARM1,HOUR_ALARM1,DAY_ALARM1, //alarm1 +CONTROL,STATUS,TRICKLE_CHARGER}; + + +#define DSNAME "ds1305rtc" +#define DS_DRIVER_V "1.0" +#define DSMAJORNUM 0 + +/*CONTROL bits*/ +#define EOSC 0x80 +#define WP 0x40 +#define INTCN 4 +#define AIE1 2 +#define AIE0 1 + +#define INT0 0x04 +#define INT1 0x08 + +#define DDQS *(volatile u8 *)(MCF_MBAR + 0x100021) +#define SETQS *(volatile u8 *)(MCF_MBAR + 0x100035) +#define CLEARQS *(volatile u8 *)(MCF_MBAR + 0x100049) + +#define RTC_CS_MASK 0x40 +#define RTC_CE_SETUP() DDQS|=RTC_CS_MASK +#define RTC_CE_ON() qspi_mutex_down();SETQS=RTC_CS_MASK; +#define RTC_CE_OFF() CLEARQS=~RTC_CS_MASK;qspi_mutex_up(); + + +typedef struct rtc_qspi_device{ +qspi_dev *qspi; +}rtc_qspi_device; + +#define SUCCESS 1 + +#define TIME2RTC(data) (((data/10)<<4)+(data%10)) +#define RTC2TIME(data) (((data>>4)*10)+(data&0x0f)) + +#define RTC_SECONDS(dev) RTC_Read_Register(dev,SEC) +#define RTC_MINUTES(dev) RTC_Read_Register(dev,MIN) +#define RTC_HOURS(dev) RTC_Read_Register(dev,HOURS) +#define RTC_DAY(dev) RTC_Read_Register(dev,DAY) +#define RTC_DATE(dev) RTC_Read_Register(dev,DATE) +#define RTC_MONTH(dev) RTC_Read_Register(dev,MONTH) +#define RTC_YEAR(dev) RTC_Read_Register(dev,YEAR) + + +#define RTC_SET_SECONDS(dev,data) RTC_Write_Register(dev,SEC,TIME2RTC(data)) +#define RTC_SET_MINUTES(dev,data) RTC_Write_Register(dev,MIN,TIME2RTC(data)) +#define RTC_SET_HOURS(dev,data) RTC_Write_Register(dev,HOURS,TIME2RTC(data)) +#define RTC_SET_DAY(dev,data) RTC_Write_Register(dev,DAY,TIME2RTC(data)) +#define RTC_SET_DATE(dev,data) RTC_Write_Register(dev,DATE,TIME2RTC(data)) +#define RTC_SET_MONTH(dev,data) RTC_Write_Register(dev,MONTH,TIME2RTC(data)) +#define RTC_SET_YEAR(dev,data) RTC_Write_Register(dev,YEAR,TIME2RTC(data)) + +#endif /*DS1305RTC_H*/ \ No newline at end of file diff --git a/include/asm-m68knommu/cs89x0_fct.h b/include/asm-m68knommu/cs89x0_fct.h new file mode 100644 index 00000000..9ae90b91 --- /dev/null +++ b/include/asm-m68knommu/cs89x0_fct.h @@ -0,0 +1,347 @@ + +/* include/asm-m68knommu/cs89x0_fct.h: arch/platformm specific code for CS89x0 + * + * Copyright (C) 2004 Georges Menie + * + */ + +#ifndef _CS89X0_FCT_H_ +#define _CS89X0_FCT_H_ + +#if defined(CONFIG_UCSIMM) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + extern unsigned char *cs8900a_hwaddr; + + if (unit != 0) + return 1; /* only one device */ + + /* set up the chip select */ + *(volatile unsigned char *)0xfffff42b |= 0x01; /* output /sleep */ + *(volatile unsigned short *)0xfffff428 |= 0x0101; /* not sleeping */ + *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ + *(volatile unsigned short *)0xfffff428 &= ~0x0202; /* irq5 fcn on */ + *(volatile unsigned short *)0xfffff102 = 0x8000; /* 0x04000000 */ + *(volatile unsigned short *)0xfffff112 = 0x01e1; /* 128k, 2ws, FLASH, en */ + + dev->base_addr = 0x10000301; + dev->irq = IRQ5_IRQ_NUM; + memcpy(dev->dev_addr, cs8900a_hwaddr, 6); + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + *(volatile unsigned short *)0xfffff302 |= 0x0080; /* +ve pol irq */ + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_UCDIMM) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + extern unsigned char *cs8900a_hwaddr; + + if (unit != 0) + return 1; /* only one device */ + + /* set up the chip select */ + *(volatile unsigned char *)0xfffff430 |= 0x08; + *(volatile unsigned char *)0xfffff433 |= 0x08; + *(volatile unsigned char *)0xfffff431 |= (0x08); /* sleep */ + *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ + *(volatile unsigned short *)0xfffff428 &= ~0x0202; /* irq5 fcn on */ + *(volatile unsigned short *)0xfffff102 = 0x8000; /* 0x04000000 */ + *(volatile unsigned short *)0xfffff112 = 0x01e1; /* 128k, 2ws, FLASH, en */ + + dev->base_addr = 0x10000301; + dev->irq = IRQ5_IRQ_NUM; + memcpy(dev->dev_addr, cs8900a_hwaddr, 6); + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + *(volatile unsigned short *)0xfffff302 |= 0x0080; /* +ve pol irq */ + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_DRAGEN2) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + if (net_debug) + printk("cs89x0:cs89x0_hw_init_hook(%d)\n", unit); + + if (unit != 0) + return 1; /* only one device */ + + dev->base_addr = 0x08000041; + dev->irq = INT1_IRQ_NUM; + memcpy(dev->dev_addr, (void *) 0x400fffa, 6); + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_EZ328LCD) || defined(CONFIG_VZ328LCD) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + if (unit != 0) + return 1; /* only one device */ + + dev->base_addr = 0x2000301; + dev->irq = IRQ5_IRQ_NUM; + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x10; + dev->dev_addr[2] = 0x8b; + dev->dev_addr[3] = 0xf1; + dev->dev_addr[4] = 0xda; + dev->dev_addr[5] = 0x01; + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + *(volatile unsigned short *)0xfffff302 |= 0x0080; /* +ve pol irq */ + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_ARCH_TA7S) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + if (unit != 0) + return 1; /* only one device */ + + dev->base_addr = 0x10000001; + dev->irq = IRQ_CSL_USER_0; + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + if (request_irq(dev->irq, &net_interrupt, SA_INTERRUPT, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_DRAGONIXVZ) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + extern unsigned char cs8900a_hwaddr1[6]; + + if (unit != 0) + return 1; /* only one device */ + + /* set up the chip select */ + *(volatile unsigned char *)0xfffff41b &= ~0x80; /* input irq6 */ + *(volatile unsigned char *)0x04000105= 0x01; /* nSleep=1 */ + + dev->base_addr = 0x4000001; + dev->irq = IRQ6_IRQ_NUM; + memcpy(dev->dev_addr, cs8900a_hwaddr1, 6); + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + *(volatile unsigned short *)0xfffff302 &= ~0x1100; /* -ve pol, level sensitive irq */ + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_CWVZ328) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + if (unit != 0) + return 1; /* only one device */ + + *(volatile unsigned char *)0xfffff42b |= 0x01; /* output /sleep */ + *(volatile unsigned short *)0xfffff428 |= 0x0101; /* not sleeping */ + *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ + *(volatile unsigned short *)0xfffff428 &= ~0x0202; /* irq5 fcn on */ + *(volatile unsigned short *)0xfffff102 = 0x2000; /* 0x4000000 */ + *(volatile unsigned short *)0xfffff112 = 0x01e1; /* 128k, 2ws, FLASH, en */ + + dev->base_addr = 0x4000001; + dev->irq = IRQ5_IRQ_NUM; + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x10; + dev->dev_addr[2] = 0x8b; + dev->dev_addr[3] = 0xf1; + dev->dev_addr[4] = 0xda; + dev->dev_addr[5] = 0x01; + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + *(volatile unsigned short *)0xfffff302 |= 0x0080; /* +ve pol irq */ + if (request_irq(dev->irq, &net_interrupt, IRQ_FLG_STD, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_EXCALIBUR) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + extern unsigned char *cs8900a_hwaddr; + + if (unit != 0) + return 1; /* only one device */ + + *(char *)na_enet = 0; /* Reset the chip to a usable state. */ +#if 0 /* this is done in cs89x0_probe1 if (ioaddr & 1) flag is set */ + dev->base_addr = ioaddr; + if (readreg(dev, PP_ChipID) != CHIP_EISA_ID_SIG) { + return -ENODEV; + } +#endif +#ifdef na_enet_reset_n + *(volatile unsigned char*)na_enet_reset_n=3; +#endif + + dev->base_addr = na_enet+1; + dev->irq = na_enet_irq; + memcpy(dev->dev_addr, cs8900a_hwaddr, 6); + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + if (request_irq(dev->irq, &net_interrupt, SA_INTERRUPT, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#elif defined(CONFIG_HYPERSTONE_CS89X0) + +static inline int cs89x_hw_init_hook(struct net_device *dev, int unit) +{ + if (unit != 0) + return 1; /* only one device */ + + dev->base_addr = 0x01000301; + dev->irq = CONFIG_HYPERSTONE_CS89X0_IRQ-1; + memcpy(dev->dev_addr, "\x48\x79\x4c\x6e\x78\x30", 6); /* FIXME */ + + return 0; +} + +static inline int cs89x_set_irq(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + writereg(dev, PP_BusCTL, 0); /* Disable Interrupts. */ + write_irq(dev, lp->chip_type, dev->irq); + if (request_irq(dev->irq, &net_interrupt, SA_INTERRUPT, dev->name, dev)) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); + return 1; + } + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); + + return 0; +} + +#endif + +#endif diff --git a/include/asm-m68knommu/dma-mapping.h b/include/asm-m68knommu/dma-mapping.h index 5622b855..6aeab18e 100644 --- a/include/asm-m68knommu/dma-mapping.h +++ b/include/asm-m68knommu/dma-mapping.h @@ -1,9 +1,10 @@ #ifndef _M68KNOMMU_DMA_MAPPING_H #define _M68KNOMMU_DMA_MAPPING_H - #ifdef CONFIG_PCI #include +#else +#include #endif #endif /* _M68KNOMMU_DMA_MAPPING_H */ diff --git a/include/asm-m68knommu/dma.h b/include/asm-m68knommu/dma.h index 3338001a..3f20419c 100644 --- a/include/asm-m68knommu/dma.h +++ b/include/asm-m68knommu/dma.h @@ -39,6 +39,8 @@ #define MAX_M68K_DMA_CHANNELS 4 #elif defined(CONFIG_M5272) #define MAX_M68K_DMA_CHANNELS 1 +#elif defined(CONFIG_M532x) +#define MAX_M68K_DMA_CHANNELS 0 #else #define MAX_M68K_DMA_CHANNELS 2 #endif diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h index 45e7a2fd..7b8f874f 100644 --- a/include/asm-m68knommu/irq.h +++ b/include/asm-m68knommu/irq.h @@ -86,5 +86,6 @@ extern void (*mach_disable_irq)(unsigned int); #define enable_irq(x) do { } while (0) #define disable_irq(x) do { } while (0) #define disable_irq_nosync(x) disable_irq(x) +#define irq_canonicalize(irq) (irq) #endif /* _M68K_IRQ_H_ */ diff --git a/include/asm-m68knommu/m520xsim.h b/include/asm-m68knommu/m520xsim.h index 1dac22ea..49d016e6 100644 --- a/include/asm-m68knommu/m520xsim.h +++ b/include/asm-m68knommu/m520xsim.h @@ -31,6 +31,16 @@ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ +/* + * SDRAM configuration registers. + */ +#define MCFSIM_SDMR 0x000a8000 /* SDRAM Mode/Extended Mode Register */ +#define MCFSIM_SDCR 0x000a8004 /* SDRAM Control Register */ +#define MCFSIM_SDCFG1 0x000a8008 /* SDRAM Configuration Register 1 */ +#define MCFSIM_SDCFG2 0x000a800c /* SDRAM Configuration Register 2 */ +#define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */ +#define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */ + #define MCF_GPIO_PAR_UART (0xA4036) #define MCF_GPIO_PAR_FECI2C (0xA4033) @@ -47,7 +57,7 @@ #define ICR_INTRCONF 0x05 #define MCFPIT_IMR MCFINTC_IMRL -#define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) +#define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1) /****************************************************************************/ #endif /* m520xsim_h */ diff --git a/include/asm-m68knommu/m528xsim.h b/include/asm-m68knommu/m528xsim.h index 1a3b1ae0..28bf783a 100644 --- a/include/asm-m68knommu/m528xsim.h +++ b/include/asm-m68knommu/m528xsim.h @@ -47,6 +47,9 @@ /* set Port AS pin for I2C or UART */ #define MCF5282_GPIO_PASPAR (volatile u16 *) (MCF_IPSBAR + 0x00100056) +/* Port UA Pin Assignment Register (8 Bit) */ +#define MCF5282_GPIO_PUAPAR 0x10005C + /* Interrupt Mask Register Register Low */ #define MCF5282_INTC0_IMRL (volatile u32 *) (MCF_IPSBAR + 0x0C0C) /* Interrupt Control Register 7 */ diff --git a/include/asm-m68knommu/machdep.h b/include/asm-m68knommu/machdep.h index 6ce28f8e..3e4905f7 100644 --- a/include/asm-m68knommu/machdep.h +++ b/include/asm-m68knommu/machdep.h @@ -7,7 +7,8 @@ struct pt_regs; struct kbd_repeat; struct mktime; -struct hwclk_time; +struct rtc_time; +struct rtc_pll_info; struct gendisk; struct buffer_head; @@ -30,8 +31,11 @@ extern void (*mach_process_int) (int irq, struct pt_regs *fp); extern unsigned long (*mach_gettimeoffset)(void); extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour, int *min, int *sec); -extern int (*mach_hwclk)(int, struct hwclk_time*); +extern int (*mach_hwclk)(int, struct rtc_time*); extern int (*mach_set_clock_mmss)(unsigned long); +extern unsigned int (*mach_get_ss)(void); +extern int (*mach_get_rtc_pll)(struct rtc_pll_info *pll); +extern int (*mach_set_rtc_pll)(struct rtc_pll_info *pll); extern void (*mach_reset)( void ); extern void (*mach_halt)( void ); extern void (*mach_power_off)( void ); diff --git a/include/asm-m68knommu/mcfqspi.h b/include/asm-m68knommu/mcfqspi.h new file mode 100644 index 00000000..28dd6329 --- /dev/null +++ b/include/asm-m68knommu/mcfqspi.h @@ -0,0 +1,30 @@ +#if !defined(MCFQSPI_H) +#define MCFQSPI_H + +#include + + +#define QSPIIOCS_DOUT_HIZ 1 /* QMR[DOHIE] set hi-z dout between transfers */ +#define QSPIIOCS_BITS 2 /* QMR[BITS] set transfer size */ +#define QSPIIOCG_BITS 3 /* QMR[BITS] get transfer size */ +#define QSPIIOCS_CPOL 4 /* QMR[CPOL] set SCK inactive state */ +#define QSPIIOCS_CPHA 5 /* QMR[CPHA] set SCK phase, 1=rising edge */ +#define QSPIIOCS_BAUD 6 /* QMR[BAUD] set SCK baud rate divider */ +#define QSPIIOCS_QCD 7 /* QDLYR[QCD] set start delay */ +#define QSPIIOCS_DTL 8 /* QDLYR[DTL] set after delay */ +#define QSPIIOCS_CONT 9 /* continuous CS asserted during transfer */ +#define QSPIIOCS_READDATA 10 /* set data send during read */ +#define QSPIIOCS_ODD_MOD 11 /* if length of buffer is a odd number, 16-bit transfers */ + /* are finalized with a 8-bit transfer */ +#define QSPIIOCS_DSP_MOD 12 /* transfers are bounded to 15/30 bytes (a multiple of 3 bytes = 1 DSP word) */ +#define QSPIIOCS_POLL_MOD 13 /* driver uses polling instead of interrupts */ + + +typedef struct qspi_read_data { + __u32 length; + __u8 *buf; /* data to send during read */ + unsigned int loop : 1; +} qspi_read_data; + + +#endif /* MCFQSPI_H */ diff --git a/include/asm-m68knommu/rtc.h b/include/asm-m68knommu/rtc.h new file mode 100644 index 00000000..eaf18ec8 --- /dev/null +++ b/include/asm-m68knommu/rtc.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h index 12309b18..2085d6ff 100644 --- a/include/asm-m68knommu/scatterlist.h +++ b/include/asm-m68knommu/scatterlist.h @@ -10,7 +10,7 @@ struct scatterlist { unsigned int length; }; -#define sg_address(sg) (page_address((sg)->page) + (sg)->offset +#define sg_address(sg) (page_address((sg)->page) + (sg)->offset) #define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) diff --git a/include/asm-m68knommu/ucontext.h b/include/asm-m68knommu/ucontext.h index 5d570ced..713a27f9 100644 --- a/include/asm-m68knommu/ucontext.h +++ b/include/asm-m68knommu/ucontext.h @@ -5,21 +5,17 @@ typedef int greg_t; #define NGREG 18 typedef greg_t gregset_t[NGREG]; -#ifdef CONFIG_FPU typedef struct fpregset { int f_pcr; int f_psr; int f_fpiaddr; int f_fpregs[8][3]; } fpregset_t; -#endif struct mcontext { int version; gregset_t gregs; -#ifdef CONFIG_FPU fpregset_t fpregs; -#endif }; #define MCONTEXT_VERSION 2 @@ -29,9 +25,7 @@ struct ucontext { struct ucontext *uc_link; stack_t uc_stack; struct mcontext uc_mcontext; -#ifdef CONFIG_FPU unsigned long uc_filler[80]; -#endif sigset_t uc_sigmask; /* mask last for extensibility */ }; diff --git a/include/asm-nios2nommu/ChangeLog b/include/asm-nios2nommu/ChangeLog new file mode 100644 index 00000000..94aaa273 --- /dev/null +++ b/include/asm-nios2nommu/ChangeLog @@ -0,0 +1,14 @@ +2004-06-29 Ken Hill + + * bitops.h (find_next_zero_bit): Fix problem with with masking for found_first + handling. The masking of the upper bits for size < 32 bits would set all + the bits to 1. Removing any zero's there may have been. + +2004-06-02 Ken Hill + + * processor.h (TASK_SIZE): Change na_sdram_end to nasys_program_mem_end to remove + dependancy on quartus memory component name. + + * page.h (PAGE_OFFSET): Change na_sdram to nasys_program_mem to remove + dependancy on quartus memory component name. + diff --git a/include/asm-nios2nommu/a.out.h b/include/asm-nios2nommu/a.out.h new file mode 100644 index 00000000..82976876 --- /dev/null +++ b/include/asm-nios2nommu/a.out.h @@ -0,0 +1,85 @@ +/* $Id: a.out.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ */ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __NIOS2NOMMU_A_OUT_H__ +#define __NIOS2NOMMU_A_OUT_H__ + +#define SPARC_PGSIZE 0x1000 /* Thanks to the sun4 architecture... */ +#define SEGMENT_SIZE SPARC_PGSIZE /* whee... */ + +struct exec { + unsigned char a_dynamic:1; /* A __DYNAMIC is in this image */ + unsigned char a_toolversion:7; + unsigned char a_machtype; + unsigned short a_info; + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of bss, in bytes */ + unsigned long a_syms; /* length of symbol table, in bytes */ + unsigned long a_entry; /* where program begins */ + unsigned long a_trsize; + unsigned long a_drsize; +}; + +#define INIT_EXEC { \ + .a_dynamic = 0, \ + .a_toolversion = 0, \ + .a_machtype = 0, \ + .a_info = 0, \ + .a_text = 0, \ + .a_data = 0, \ + .a_bss = 0, \ + .a_syms = 0, \ + .a_entry = 0, \ + .a_trsize = 0, \ + .a_drsize = 0, \ +} + +/* Where in the file does the text information begin? */ +#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec)) + +/* Where do the Symbols start? */ +#define N_SYMOFF(x) (N_TXTOFF(x) + (x).a_text + \ + (x).a_data + (x).a_trsize + \ + (x).a_drsize) + +/* Where does text segment go in memory after being loaded? */ +#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ + ((x).a_entry < SPARC_PGSIZE)) ? \ + 0 : SPARC_PGSIZE) + +/* And same for the data segment.. */ +#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ + (N_TXTADDR(x) + (x).a_text) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE + +#endif + +#endif /* __NIOS2NOMMU_A_OUT_H__ */ diff --git a/include/asm-nios2nommu/altera_juart.h b/include/asm-nios2nommu/altera_juart.h new file mode 100644 index 00000000..da6320df --- /dev/null +++ b/include/asm-nios2nommu/altera_juart.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------ + * + * linux/drivers/serial/altera_juart.h + * + * Driver for Altera JTAG UART core with Avalon interface + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * History: + * Jun/20/2005 DGT Microtronix Datacom NiosII + * + -----------------------------------------------------------------------*/ + +#ifndef _ALTERA_JUART_H_ + #define _ALTERA_JUART_H_ + + /* jtag uart details needed outside of the driver itself: */ + /* by: arch/kernel/start.c - boot time error message(s) */ + + void jtaguart_console_write + ( struct console *co, + const char *s, + unsigned int count); + +#endif /* _ALTERA_JUART_H_ */ diff --git a/include/asm-nios2nommu/asm-macros.h b/include/asm-nios2nommu/asm-macros.h new file mode 100644 index 00000000..9dda7cd9 --- /dev/null +++ b/include/asm-nios2nommu/asm-macros.h @@ -0,0 +1,331 @@ +/* + * Macro used to simplify coding multi-line assembler. + * Some of the bit test macro can simplify down to one line + * depending on the mask value. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * ANDs reg2 with mask and places the result in reg1. + * + * You cannnot use the same register for reg1 & reg2. + */ + +.macro ANDI32 reg1,reg2,mask + .if \mask & 0xffff + .if \mask & 0xffff0000 + movhi \reg1,%hi(\mask) + movui \reg1,%lo(\mask) + and \reg1,\reg1,\reg2 + .else + andi \reg1,\reg2,%lo(\mask) + .endif + .else + andhi \reg1,\reg2,%hi(\mask) + .endif +.endm + +/* + * ORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro ORI32 reg1,reg2,mask + .if \mask & 0xffff + .if \mask & 0xffff0000 + orhi \reg1,\reg2,%hi(\mask) + ori \reg1,\reg2,%lo(\mask) + .else + ori \reg1,\reg2,%lo(\mask) + .endif + .else + orhi \reg1,\reg2,%hi(\mask) + .endif +.endm + +/* + * XORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro XORI32 reg1,reg2,mask + .if \mask & 0xffff + .if \mask & 0xffff0000 + xorhi \reg1,\reg2,%hi(\mask) + xori \reg1,\reg1,%lo(\mask) + .else + xori \reg1,\reg2,%lo(\mask) + .endif + .else + xorhi \reg1,\reg2,%hi(\mask) + .endif +.endm + +/* + * This is a support macro for BTBZ & BTBNZ. It checks + * the bit to make sure it is valid 32 value. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BT reg1,reg2,bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1,\reg2,(1 << \bit) + .else + andhi \reg1,\reg2,(1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBZ reg1,reg2,bit,label + BT \reg1,\reg2,\bit + beq \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is non-zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBNZ reg1,reg2,bit,label + BT \reg1,\reg2,\bit + bne \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTC reg1,reg2,bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1,\reg2,(1 << \bit) + xori \reg2,\reg2,(1 << \bit) + .else + andhi \reg1,\reg2,(1 << (\bit - 16)) + xorhi \reg2,\reg2,(1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTS reg1,reg2,bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1,\reg2,(1 << \bit) + ori \reg2,\reg2,(1 << \bit) + .else + andhi \reg1,\reg2,(1 << (\bit - 16)) + orhi \reg2,\reg2,(1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTR reg1,reg2,bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1,\reg2,(1 << \bit) + andi \reg2,\reg2,%lo(~(1 << \bit)) + .else + andhi \reg1,\reg2,(1 << (\bit - 16)) + andhi \reg2,\reg2,%lo(~(1 << (\bit - 16))) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBZ reg1,reg2,bit,label + BTC \reg1,\reg2,\bit + beq \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBNZ reg1,reg2,bit,label + BTC \reg1,\reg2,\bit + bne \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBZ reg1,reg2,bit,label + BTS \reg1,\reg2,\bit + beq \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBNZ reg1,reg2,bit,label + BTS \reg1,\reg2,\bit + bne \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBZ reg1,reg2,bit,label + BTR \reg1,\reg2,\bit + bne \reg1,r0,\label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBNZ reg1,reg2,bit,label + BTR \reg1,\reg2,\bit + bne \reg1,r0,\label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the all the bits in the mask are zero it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBZ reg1,reg2,mask,label + ANDI32 \reg1,\reg2,\mask + beq \reg1,r0,\label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the any of the bits in the mask are 1 it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBNZ reg1,reg2,mask,label + ANDI32 \reg1,\reg2,\mask + bne \reg1,r0,\label +.endm + +/* + * Pushes reg onto the stack. + */ + +.macro PUSH reg + addi sp,sp,-4 + stw \reg,0(sp) +.endm + +/* + * Pops the top of the stack into reg. + */ + +.macro POP reg + ldw \reg,0(sp) + addi sp,sp,4 +.endm + +/* + * Clears reg + */ + +.macro CLR reg + mov \reg,r0 +.endm + +/* + * The preprocessor macro does not work for + * the nios2 compiler. Undefine ENTRY and define + * a real assembler macro. + */ +#undef ENTRY +#define ENTRY(name) ASM_ENTRY name + +.macro ASM_ENTRY name +.globl \name +__ALIGN + \name: +.endm diff --git a/include/asm-nios2nommu/atomic.h b/include/asm-nios2nommu/atomic.h new file mode 100644 index 00000000..fb627de2 --- /dev/null +++ b/include/asm-nios2nommu/atomic.h @@ -0,0 +1,146 @@ +#ifndef __ASM_SH_ATOMIC_H +#define __ASM_SH_ATOMIC_H + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * + */ + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) ((v)->counter = (i)) + +#include + +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ + +static __inline__ void atomic_add(int i, atomic_t * v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v += i; + local_irq_restore(flags); +} + +static __inline__ void atomic_sub(int i, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v -= i; + local_irq_restore(flags); +} + +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp += i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp -= i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +/* + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) + +#define atomic_inc(v) atomic_add(1,(v)) +#define atomic_dec(v) atomic_sub(1,(v)) + +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + int ret; + unsigned long flags; + + local_irq_save(flags); + ret = v->counter; + if (likely(ret == old)) + v->counter = new; + local_irq_restore(flags); + + return ret; +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline int atomic_add_unless(atomic_t *v, int a, int u) +{ + int ret; + unsigned long flags; + + local_irq_save(flags); + ret = v->counter; + if (ret != u) + v->counter += a; + local_irq_restore(flags); + + return ret != u; +} +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v &= ~mask; + local_irq_restore(flags); +} + +static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + *(long *)v |= mask; + local_irq_restore(flags); +} + +/* Atomic operations are already serializing on SH */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#include +#endif /* __ASM_SH_ATOMIC_H */ diff --git a/include/asm-nios2nommu/auxvec.h b/include/asm-nios2nommu/auxvec.h new file mode 100644 index 00000000..fc21e4db --- /dev/null +++ b/include/asm-nios2nommu/auxvec.h @@ -0,0 +1,4 @@ +#ifndef __ASM_SH_AUXVEC_H +#define __ASM_SH_AUXVEC_H + +#endif /* __ASM_SH_AUXVEC_H */ diff --git a/include/asm-nios2nommu/bitops.h b/include/asm-nios2nommu/bitops.h new file mode 100644 index 00000000..7bf18620 --- /dev/null +++ b/include/asm-nios2nommu/bitops.h @@ -0,0 +1,11 @@ +#ifndef __ASM_NIOS2NOMMU_BITOPS_H +#define __ASM_NIOS2NOMMU_BITOPS_H + +#ifdef __KERNEL__ +#include +#include +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +#endif /* __KERNEL__ */ + +#endif /* __ASM_NIOS2NOMMU_BITOPS_H */ diff --git a/include/asm-nios2nommu/bootinfo.h b/include/asm-nios2nommu/bootinfo.h new file mode 100644 index 00000000..ee8c39ef --- /dev/null +++ b/include/asm-nios2nommu/bootinfo.h @@ -0,0 +1,2 @@ + +/* Nothing for nios2nommu */ diff --git a/include/asm-nios2nommu/bug.h b/include/asm-nios2nommu/bug.h new file mode 100644 index 00000000..d99ab08a --- /dev/null +++ b/include/asm-nios2nommu/bug.h @@ -0,0 +1,4 @@ +#ifndef _MNIOS2NOMMU_BUG_H +#define _MNIOS2NOMMU_BUG_H +#include +#endif diff --git a/include/asm-nios2nommu/bugs.h b/include/asm-nios2nommu/bugs.h new file mode 100644 index 00000000..a0753ebd --- /dev/null +++ b/include/asm-nios2nommu/bugs.h @@ -0,0 +1,40 @@ +#ifndef __ASM_NIOS_BUGS_H +#define __ASM_NIOS_BUGS_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/bugs.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +static void check_bugs(void) +{ +} + +#endif diff --git a/include/asm-nios2nommu/byteorder.h b/include/asm-nios2nommu/byteorder.h new file mode 100644 index 00000000..960b6d3e --- /dev/null +++ b/include/asm-nios2nommu/byteorder.h @@ -0,0 +1,38 @@ +#ifndef __ASM_NIOS_BYTEORDER_H +#define __ASM_NIOS_BYTEORDER_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/byteorder.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#include + +#endif + diff --git a/include/asm-nios2nommu/cache.h b/include/asm-nios2nommu/cache.h new file mode 100644 index 00000000..82bbd143 --- /dev/null +++ b/include/asm-nios2nommu/cache.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __ARCH_NIOS2NOMMU_CACHE_H +#define __ARCH_NIOS2NOMMU_CACHE_H + +#include + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES nasys_icache_line_size /* 32, this need to be at least 1 */ +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) +#define L1_CACHE_SHIFT 5 + + +#define __cacheline_aligned +#define ____cacheline_aligned + +#endif diff --git a/include/asm-nios2nommu/cachectl.h b/include/asm-nios2nommu/cachectl.h new file mode 100644 index 00000000..39d7d9d0 --- /dev/null +++ b/include/asm-nios2nommu/cachectl.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2NOMMU_CACHECTL_H +#define _NIOS2NOMMU_CACHECTL_H + +/* Definitions for the cacheflush system call. */ + +#define FLUSH_SCOPE_LINE 1 /* Flush a cache line */ +#define FLUSH_SCOPE_PAGE 2 /* Flush a page */ +#define FLUSH_SCOPE_ALL 3 /* Flush the whole cache -- superuser only */ + +#define FLUSH_CACHE_DATA 1 /* Writeback and flush data cache */ +#define FLUSH_CACHE_INSN 2 /* Flush instruction cache */ +#define FLUSH_CACHE_BOTH 3 /* Flush both caches */ + +#endif /* _NIOS2NOMMU_CACHECTL_H */ diff --git a/include/asm-nios2nommu/cacheflush.h b/include/asm-nios2nommu/cacheflush.h new file mode 100644 index 00000000..4543201d --- /dev/null +++ b/include/asm-nios2nommu/cacheflush.h @@ -0,0 +1,59 @@ +#ifndef _NIOS2NOMMU_CACHEFLUSH_H +#define _NIOS2NOMMU_CACHEFLUSH_H + +/* + * Ported from m68knommu. + * + * (C) Copyright 2003, Microtronix Datacom Ltd. + * (C) Copyright 2000-2002, Greg Ungerer + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include + +extern void cache_push (unsigned long vaddr, int len); +extern void dcache_push (unsigned long vaddr, int len); +extern void icache_push (unsigned long vaddr, int len); +extern void cache_push_all (void); +extern void cache_clear (unsigned long paddr, int len); + +#define flush_cache_all() __flush_cache_all() +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) cache_push(start, end - start) +#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_dcache_range(start,end) dcache_push(start, end - start) +#define flush_dcache_page(page) do { } while (0) +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) +#define flush_icache_range(start,end) cache_push(start, end - start) +#define flush_icache_page(vma,pg) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + + +extern inline void __flush_cache_all(void) +{ + cache_push_all(); +} + +#endif /* _NIOS2NOMMU_CACHEFLUSH_H */ diff --git a/include/asm-nios2nommu/checksum.h b/include/asm-nios2nommu/checksum.h new file mode 100644 index 00000000..1f6879e5 --- /dev/null +++ b/include/asm-nios2nommu/checksum.h @@ -0,0 +1,320 @@ +#ifndef __NIOS2_CHECKSUM_H +#define __NIOS2_CHECKSUM_H + +/* checksum.h: IP/UDP/TCP checksum routines on the NIOS. + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1995 Miguel de Icaza + * Copyright(C) 1996 David S. Miller + * Copyright(C) 2001 Ken Hill + * Copyright(C) 2004 Microtronix Datacom Ltd. + * + * derived from: + * Alpha checksum c-code + * ix86 inline assembly + * Spar nommu + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ + +extern inline unsigned short csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + barrier(); + __asm__ __volatile__( +" add %0, %3, %0\n" +" bgeu %0, %3, 1f\n" +" addi %0, %0, 1\n" +"1: add %0, %4, %0\n" +" bgeu %0, %4, 1f\n" +" addi %0, %0, 1\n" +"1: add %0, %5, %0\n" +" bgeu %0, %5, 1f\n" +" addi %0, %0, 1\n" +"1:\n" +/* + We need the carry from the addition of 16-bit + significant addition, so we zap out the low bits + in one half, zap out the high bits in another, + shift them both up to the top 16-bits of a word + and do the carry producing addition, finally + shift the result back down to the low 16-bits. + + Actually, we can further optimize away two shifts + because we know the low bits of the original + value will be added to zero-only bits so cannot + affect the addition result nor the final carry + bit. +*/ +" slli %1,%0, 16\n" /* Need a copy to fold with */ + /* Bring the LOW 16 bits up */ +" add %0, %1, %0\n" /* add and set carry, neat eh? */ +" cmpltu r15, %0, %1\n" /* get remaining carry bit */ +" srli %0, %0, 16\n" /* shift back down the result */ +" add %0, %0, r15\n" +" nor %0, %0, %0\n" /* negate */ + : "=&r" (sum), "=&r" (saddr) + : "0" (sum), "1" (saddr), "r" (ntohl(len+proto)), "r" (daddr) + : "r15"); + return ((unsigned short) sum); + barrier(); +} + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + + extern inline unsigned short from32to16(unsigned long x) + { + barrier(); + __asm__ __volatile__( + "add %0, %1, %0\n" + "cmpltu r15, %0, %1\n" + "srli %0, %0, 16\n" + "add %0, %0, r15\n" + : "=r" (x) + : "r" (x << 16), "0" (x) + : "r15"); + return x; + barrier(); + } + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +extern inline unsigned long do_csum(const unsigned char * buff, int len) +{ + int odd, count; + unsigned long result = 0; + + barrier(); + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { +////result = *buff; // dgt: Big endian + result = *buff << 8; // dgt: Little endian + + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += *buff; /* This is little machine, byte is right */ + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; + barrier(); + } + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +/* ihl is always 5 or greater, almost always is 5, iph is always word + * aligned but can fail to be dword aligned very often. + */ + + extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl) + { + unsigned int sum; + + barrier(); + __asm__ __volatile__( +" andi r8, %1, 2\n" /* Remember original alignment */ +" ldw %0, (%1)\n" /* 16 or 32 bit boundary */ +" beq r8, r0, 1f\n" /* Aligned on 32 bit boundary, go */ +" srli %0, %0, 16\n" /* Get correct 16 bits */ +" addi %2, %2, -1\n" /* Take off for 4 bytes, pickup last 2 at end */ +" addi %1, %1, 2\n" /* Adjust pointer to 32 bit boundary */ +" br 2f\n" +"1:\n" +" addi %2, %2, -1\n" +" addi %1, %1, 4\n" /* Bump ptr a long word */ +"2:\n" +" ldw r9, (%1)\n" +"1:\n" +" add %0, r9, %0\n" +" bgeu %0, r9, 2f\n" +" addi %0, %0, 1\n" +"2:\n" +" addi %1, %1, 4\n" +" addi %2, %2, -1\n" +" ldw r9, (%1)\n" +" bne %2, r0, 1b\n" +" beq r8, r0, 1f\n" /* 32 bit boundary time to leave */ +" srli r9, r9, 16\n" /* 16 bit boundary, get correct 16 bits */ +" add %0, r9, %0\n" +" bgeu %0, r9, 1f\n" +" addi %0, %0, 1\n" +"1:\n" +" slli %2, %0, 16\n" +" add %0, %2, %0\n" +" cmpltu r8, %0, %2\n" +" srli %0, %0, 16\n" +" add %0, %0, r8\n" +" nor %0, %0, %0\n" + : "=&r" (sum), "=&r" (iph), "=&r" (ihl) + : "1" (iph), "2" (ihl) + : "r8", "r9"); + return sum; + barrier(); + } + +/*these 2 functions are now in checksum.c */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); +unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +extern inline unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) +{ + barrier(); + if (csum_err) *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); + barrier(); +} + +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy ((src), (dst), (len), (sum)) + + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + barrier(); + return ~from32to16(do_csum(buff,len)); + barrier(); +} + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +#define csum_partial_copy_fromuser(s, d, l, w) \ + csum_partial_copy((char *) (s), (d), (l), (w)) + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +/* + * Fold a partial checksum without adding pseudo headers + */ +extern __inline__ unsigned int csum_fold(unsigned int sum) +{ + barrier(); + __asm__ __volatile__( + "add %0, %1, %0\n" + "cmpltu r8, %0, %1\n" + "srli %0, %0, 16\n" + "add %0, %0, r8\n" + "nor %0, %0, %0\n" + : "=r" (sum) + : "r" (sum << 16), "0" (sum) + : "r8"); + return sum; + barrier(); +} + + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + barrier(); + __asm__ __volatile__( + "add %0, %1, %0\n" + "cmpltu r8, %0, %1\n" + "add %0, %0, r8\n" /* add carry */ + "add %0, %2, %0\n" + "cmpltu r8, %0, %2\n" + "add %0, %0, r8\n" /* add carry */ + "add %0, %3, %0\n" + "cmpltu r8, %0, %3\n" + "add %0, %0, r8\n" /* add carry */ + : "=r" (sum), "=r" (saddr) + : "r" (daddr), "r" ( (ntohs(len)<<16) + (proto*256) ), + "0" (sum), + "1" (saddr) + : "r8"); + + return sum; + barrier(); +} + + +#endif /* (__NIOS2_CHECKSUM_H) */ diff --git a/include/asm-nios2nommu/cprefix.h b/include/asm-nios2nommu/cprefix.h new file mode 100644 index 00000000..49832114 --- /dev/null +++ b/include/asm-nios2nommu/cprefix.h @@ -0,0 +1,38 @@ +/* cprefix.h: This file is included by assembly source which needs + * to know what the c-label prefixes are. The newer versions + * of cpp that come with gcc predefine such things to help + * us out. The reason this stuff is needed is to make + * solaris compiles of the kernel work. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __NIOS2_CPREFIX_H +#define __NIOS2_CPREFIX_H + +#define C_LABEL_PREFIX + +#define CONCAT(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a##b + +#define C_LABEL(name) CONCAT(C_LABEL_PREFIX, name) + +#endif /* !(__NIOS2_CPREFIX_H) */ diff --git a/include/asm-nios2nommu/cpumask.h b/include/asm-nios2nommu/cpumask.h new file mode 100644 index 00000000..86fb3652 --- /dev/null +++ b/include/asm-nios2nommu/cpumask.h @@ -0,0 +1,28 @@ +/* + * All rights reserved. + * + * Copyright (C) 2004, Microtronix Datacom 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ASM_NIOS2NOMMU_CPUMASK_H +#define _ASM_NIOS2NOMMU_CPUMASK_H + +#include + +#endif /* _ASM_NIOS2NOMMU_CPUMASK_H */ diff --git a/include/asm-nios2nommu/cputime.h b/include/asm-nios2nommu/cputime.h new file mode 100644 index 00000000..370e4f25 --- /dev/null +++ b/include/asm-nios2nommu/cputime.h @@ -0,0 +1,31 @@ +/* + * cputime.h + * (C) Copyright 2004, Microtronix Datacom Ltd. + * + * Taken from m68knommu + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2NOMMU_CPUTIME_H +#define __NIOS2NOMMU_CPUTIME_H + +#include + +#endif /* __NIOS@NOMMU_CPUTIME_H */ diff --git a/include/asm-nios2nommu/current.h b/include/asm-nios2nommu/current.h new file mode 100644 index 00000000..5ac1dbc2 --- /dev/null +++ b/include/asm-nios2nommu/current.h @@ -0,0 +1,39 @@ +#ifndef _NIOS2NOMMU_CURRENT_H +#define _NIOS2NOMMU_CURRENT_H +/* + * current.h + * (C) Copyright 2000, Lineo, David McCullough + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +struct task_struct; + +static inline struct task_struct *get_current(void) +{ + return(current_thread_info()->task); +} + +#define current get_current() + +#endif /* _NIOS2NOMMU_CURRENT_H */ diff --git a/include/asm-nios2nommu/delay.h b/include/asm-nios2nommu/delay.h new file mode 100644 index 00000000..da0a1841 --- /dev/null +++ b/include/asm-nios2nommu/delay.h @@ -0,0 +1,96 @@ +#ifndef _NIOS_DELAY_H +#define _NIOS_DELAY_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/delay.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +extern __inline__ void __delay(unsigned long loops) +{ + int dummy; + + __asm__ __volatile__( + "1: \n\t" + " beq %0,zero,2f\n\t" + " addi %0, %0, -1\n\t" + " br 1b\n\t" + "2: \n\t" + + : "=r" (dummy) /* Need output for optimizer */ + + : "0" (loops) /* %0 Input */ + ); +} + +/* + * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so + * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. + * + * The mul instruction gives us loops = (a * b) / 2^32. + * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 + * because this lets us support a wide range of HZ and + * loops_per_jiffy values without either a or b overflowing 2^32. + * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and + * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 + * (which corresponds to ~3800 bogomips at HZ = 100). + * -- paulus + */ +#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ +#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ + +extern unsigned long loops_per_jiffy; + +extern __inline__ void __udelay(unsigned int x) +{ + unsigned int loops; + + __asm__("mulxuu %0,%1,%2" : "=r" (loops) : + "r" (x), "r" (loops_per_jiffy * 226)); + __delay(loops); +} + +extern __inline__ void __ndelay(unsigned int x) +{ + unsigned int loops; + + __asm__("mulxuu %0,%1,%2" : "=r" (loops) : + "r" (x), "r" (loops_per_jiffy * 5)); + __delay(loops); +} + +extern void __bad_udelay(void); /* deliberately undefined */ +extern void __bad_ndelay(void); /* deliberately undefined */ + +#define udelay(n) (__builtin_constant_p(n)? \ + ((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \ + __udelay((n) * (19 * HZ))) + +#define ndelay(n) (__builtin_constant_p(n)? \ + ((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \ + __ndelay((n) * HZ)) + +#define muldiv(a, b, c) (((a)*(b))/(c)) + +#endif /* defined(_NIOS_DELAY_H) */ diff --git a/include/asm-nios2nommu/div64.h b/include/asm-nios2nommu/div64.h new file mode 100644 index 00000000..68d72e44 --- /dev/null +++ b/include/asm-nios2nommu/div64.h @@ -0,0 +1,31 @@ +#ifndef __ASMNIOS_DIV64_H +#define __ASMNIOS_DIV64_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/div64.h + * + * Derived from m68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#endif + diff --git a/include/asm-nios2nommu/dma-mapping.h b/include/asm-nios2nommu/dma-mapping.h new file mode 100644 index 00000000..43288634 --- /dev/null +++ b/include/asm-nios2nommu/dma-mapping.h @@ -0,0 +1,79 @@ +#ifndef _ASM_DMA_MAPPING_H +#define _ASM_DMA_MAPPING_H + +#include +#include + +void *dma_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + +void dma_free_noncoherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + +void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + +extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction); +extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction direction); +extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); +extern dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction direction); +extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, enum dma_data_direction direction); +extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, enum dma_data_direction direction); +extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction); +extern void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); +extern void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction); +extern void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction); +extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction); +extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction); +extern int dma_mapping_error(dma_addr_t dma_addr); +extern int dma_supported(struct device *dev, u64 mask); + +static inline int +dma_set_mask(struct device *dev, u64 mask) +{ + if(!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + + *dev->dma_mask = mask; + + return 0; +} + +static inline int +dma_get_cache_alignment(void) +{ + /* XXX Largest on any MIPS */ + return 128; +} + +extern int dma_is_consistent(dma_addr_t dma_addr); + +extern void dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction direction); + +#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY + +extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags); +extern void dma_release_declared_memory(struct device *dev); +extern void * dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size); + +#endif /* _ASM_DMA_MAPPING_H */ diff --git a/include/asm-nios2nommu/dma.h b/include/asm-nios2nommu/dma.h new file mode 100644 index 00000000..ea098d5f --- /dev/null +++ b/include/asm-nios2nommu/dma.h @@ -0,0 +1,63 @@ +/* $Id: dma.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ + * + * Copyright 2004 (C) Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ASM_NIOS2_DMA_H +#define _ASM_NIOS2_DMA_H + +#include +#include + +#define MAX_DMA_ADDRESS (LINUX_SDRAM_END) + +int request_dma(unsigned int, const char *); +void free_dma(unsigned int); +void enable_dma(unsigned int dmanr); +void disable_dma(unsigned int dmanr); +void set_dma_count(unsigned int dmanr, unsigned int count); +int get_dma_residue(unsigned int dmanr); +void nios2_set_dma_data_width(unsigned int dmanr, unsigned int width); + +void nios2_set_dma_handler(unsigned int dmanr, int (*handler)(void*, int), void* user); +int nios2_request_dma(const char *); + +void nios2_set_dma_mode(unsigned int dmanr, unsigned int mode); +void nios2_set_dma_rcon(unsigned int dmanr, unsigned int set); +void nios2_set_dma_wcon(unsigned int dmanr, unsigned int set); +void nios2_set_dma_raddr(unsigned int dmanr, unsigned int a); +void nios2_set_dma_waddr(unsigned int dmanr, unsigned int a); + +static inline unsigned long claim_dma_lock(void) +{ +} + +static inline void release_dma_lock(unsigned long flags) +{ +} + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* !(_ASM_NIOS2_DMA_H) */ diff --git a/include/asm-nios2nommu/elf.h b/include/asm-nios2nommu/elf.h new file mode 100644 index 00000000..94b2ac0b --- /dev/null +++ b/include/asm-nios2nommu/elf.h @@ -0,0 +1,140 @@ +#ifndef __NIOS2_ELF_H +#define __NIOS2_ELF_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/elf.h + * + * Nio2 ELF relocation types + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Jan/20/2004 dgt NiosII + * Mar/18/2004 xwt NiosII relocation types added + * + ---------------------------------------------------------------------*/ + +#include +#include + +#define R_NIOS2_NONE 0 +#define R_NIOS2_S16 1 +#define R_NIOS2_U16 2 +#define R_NIOS2_PCREL16 3 +#define R_NIOS2_CALL26 4 +#define R_NIOS2_IMM5 5 +#define R_NIOS2_CACHE_OPX 6 +#define R_NIOS2_IMM6 7 +#define R_NIOS2_IMM8 8 +#define R_NIOS2_HI16 9 +#define R_NIOS2_LO16 10 +#define R_NIOS2_HIADJ16 11 +#define R_NIOS2_BFD_RELOC_32 12 +#define R_NIOS2_BFD_RELOC_16 13 +#define R_NIOS2_BFD_RELOC_8 14 +#define R_NIOS2_GPREL 15 +#define R_NIOS2_GNU_VTINHERIT 16 +#define R_NIOS2_GNU_VTENTRY 17 +#define R_NIOS2_UJMP 18 +#define R_NIOS2_CJMP 19 +#define R_NIOS2_CALLR 20 +#define R_NIOS2_ALIGN 21 +/* Keep this the last entry. */ +#define R_NIOS2_NUM 22 + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef unsigned long elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + ((x)->e_machine == EM_ALTERA_NIOS2) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_ALTERA_NIOS2 + +#define ELF_PLAT_INIT(_r, load_addr) _r->a1 = 0 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE 0xD0000000UL + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + /* Bleech. */ \ + pr_reg[0] = regs->r1; \ + pr_reg[1] = regs->r2; \ + pr_reg[2] = regs->r3; \ + pr_reg[3] = regs->r4; \ + pr_reg[4] = regs->r5; \ + pr_reg[5] = regs->r6; \ + pr_reg[6] = regs->r7; \ + pr_reg[7] = regs->r8; \ + pr_reg[8] = regs->r9; \ + pr_reg[9] = regs->r10; \ + pr_reg[10] = regs->r11; \ + pr_reg[11] = regs->r12; \ + pr_reg[12] = regs->r13; \ + pr_reg[13] = regs->r14; \ + pr_reg[14] = regs->r15; \ + pr_reg[23] = regs->sp; \ + pr_reg[26] = regs->estatus; \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[15] = sw->r16; \ + pr_reg[16] = sw->r17; \ + pr_reg[17] = sw->r18; \ + pr_reg[18] = sw->r19; \ + pr_reg[19] = sw->r20; \ + pr_reg[20] = sw->r21; \ + pr_reg[21] = sw->r22; \ + pr_reg[22] = sw->r23; \ + pr_reg[24] = sw->fp; \ + pr_reg[25] = sw->gp; \ + } + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#endif + +#endif diff --git a/include/asm-nios2nommu/emergency-restart.h b/include/asm-nios2nommu/emergency-restart.h new file mode 100644 index 00000000..108d8c48 --- /dev/null +++ b/include/asm-nios2nommu/emergency-restart.h @@ -0,0 +1,6 @@ +#ifndef _ASM_EMERGENCY_RESTART_H +#define _ASM_EMERGENCY_RESTART_H + +#include + +#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/include/asm-nios2nommu/entry.h b/include/asm-nios2nommu/entry.h new file mode 100644 index 00000000..4b1773f8 --- /dev/null +++ b/include/asm-nios2nommu/entry.h @@ -0,0 +1,187 @@ +/* + * Hacked from m68knommu port. + * + * Copyright(C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2NOMMU_ENTRY_H +#define __NIOS2NOMMU_ENTRY_H + +#ifdef __ASSEMBLY__ + +#include +#include +#include + +/* + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers r4-r8 + * + * 0(sp) - r8 + * 4(sp) - r9 + * 8(sp) - r10 + * C(sp) - r11 + * 10(sp) - r12 + * 14(sp) - r13 + * 18(sp) - r14 + * 1C(sp) - r15 + * 20(sp) - r1 + * 24(sp) - r2 + * 28(sp) - r3 + * 2C(sp) - r4 + * 30(sp) - r5 + * 34(sp) - r6 + * 38(sp) - r7 + * 3C(sp) - orig_r2 + * 40(sp) - ra + * 44(sp) - fp + * 48(sp) - sp + * 4C(sp) - gp + * 50(sp) - estatus + * 54(sp) - status_extension + * 58(sp) - ea + * + */ + +/* process bits for task_struct.flags */ +PF_TRACESYS_OFF = 3 +PF_TRACESYS_BIT = 5 +PF_PTRACED_OFF = 3 +PF_PTRACED_BIT = 4 +PF_DTRACE_OFF = 1 +PF_DTRACE_BIT = 5 + +LENOSYS = 38 + +/* + * This defines the normal kernel pt-regs layout. + * + */ + +/* + * Standard Nios2 interrupt entry and exit macros. + * Must be called with interrupts disabled. + */ +.macro SAVE_ALL + movia r24,status_extension // Read status extension + ldw r24,0(r24) + andi r24,r24,PS_S_ASM + bne r24,r0,1f // In supervisor mode, already on kernel stack + movia r24,_current_thread // Switch to current kernel stack + ldw r24,0(r24) // using the thread_info + addi r24,r24,THREAD_SIZE_ASM-PT_REGS_SIZE + stw sp,PT_SP(r24) // Save user stack before changing + mov sp,r24 + br 2f + +1: mov r24,sp + addi sp,sp,-PT_REGS_SIZE // Backup the kernel stack pointer + stw r24,PT_SP(sp) +2: stw r1,PT_R1(sp) + stw r2,PT_R2(sp) + stw r3,PT_R3(sp) + stw r4,PT_R4(sp) + stw r5,PT_R5(sp) + stw r6,PT_R6(sp) + stw r7,PT_R7(sp) + stw r8,PT_R8(sp) + stw r9,PT_R9(sp) + stw r10,PT_R10(sp) + stw r11,PT_R11(sp) + stw r12,PT_R12(sp) + stw r13,PT_R13(sp) + stw r14,PT_R14(sp) + stw r15,PT_R15(sp) + stw r2,PT_ORIG_R2(sp) + stw ra,PT_RA(sp) + stw fp,PT_FP(sp) + stw gp,PT_GP(sp) + rdctl r24,estatus + stw r24,PT_ESTATUS(sp) + movia r24,status_extension // Read status extension + ldw r1,0(r24) + stw r1,PT_STATUS_EXTENSION(sp) // Store user/supervisor status + ORI32 r1,r1,PS_S_ASM // Set supervisor mode + stw r1,0(r24) + stw ea,PT_EA(sp) +.endm + +.macro RESTORE_ALL + ldw r1,PT_STATUS_EXTENSION(sp) // Restore user/supervisor status + movia r24,status_extension + stw r1,0(r24) + ldw r1,PT_R1(sp) // Restore registers + ldw r2,PT_R2(sp) + ldw r3,PT_R3(sp) + ldw r4,PT_R4(sp) + ldw r5,PT_R5(sp) + ldw r6,PT_R6(sp) + ldw r7,PT_R7(sp) + ldw r8,PT_R8(sp) + ldw r9,PT_R9(sp) + ldw r10,PT_R10(sp) + ldw r11,PT_R11(sp) + ldw r12,PT_R12(sp) + ldw r13,PT_R13(sp) + ldw r14,PT_R14(sp) + ldw r15,PT_R15(sp) + ldw ra,PT_RA(sp) + ldw fp,PT_FP(sp) + ldw gp,PT_GP(sp) + ldw r24,PT_ESTATUS(sp) + wrctl estatus,r24 + ldw ea,PT_EA(sp) + ldw sp,PT_SP(sp) // Restore sp last +.endm + +.macro SAVE_SWITCH_STACK + addi sp,sp,-SWITCH_STACK_SIZE + stw r16,SW_R16(sp) + stw r17,SW_R17(sp) + stw r18,SW_R18(sp) + stw r19,SW_R19(sp) + stw r20,SW_R20(sp) + stw r21,SW_R21(sp) + stw r22,SW_R22(sp) + stw r23,SW_R23(sp) + stw fp,SW_FP(sp) + stw gp,SW_GP(sp) + stw ra,SW_RA(sp) +.endm + +.macro RESTORE_SWITCH_STACK + ldw r16,SW_R16(sp) + ldw r17,SW_R17(sp) + ldw r18,SW_R18(sp) + ldw r19,SW_R19(sp) + ldw r20,SW_R20(sp) + ldw r21,SW_R21(sp) + ldw r22,SW_R22(sp) + ldw r23,SW_R23(sp) + ldw fp,SW_FP(sp) + ldw gp,SW_GP(sp) + ldw ra,SW_RA(sp) + addi sp,sp,SWITCH_STACK_SIZE +.endm + +#endif /* __ASSEMBLY__ */ +#endif /* __NIOS2NOMMU_ENTRY_H */ diff --git a/include/asm-nios2nommu/errno.h b/include/asm-nios2nommu/errno.h new file mode 100644 index 00000000..c2caf217 --- /dev/null +++ b/include/asm-nios2nommu/errno.h @@ -0,0 +1,6 @@ +#ifndef _NIOS2NOMMU_ERRNO_H +#define _NIOS2NOMMU_ERRNO_H + +#include + +#endif /* _NIOS2NOMMU_ERRNO_H */ diff --git a/include/asm-nios2nommu/fcntl.h b/include/asm-nios2nommu/fcntl.h new file mode 100644 index 00000000..8b210445 --- /dev/null +++ b/include/asm-nios2nommu/fcntl.h @@ -0,0 +1,110 @@ +/* + * This file came from the m68k port. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _NIOS2_FCNTL_H +#define _NIOS2_FCNTL_H + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ +#define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ +#define O_LARGEFILE 0400000 +#define O_NOATIME 01000000 + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get close_on_exec */ +#define F_SETFD 2 /* set/clear close_on_exec */ +#define F_GETFL 3 /* get file->f_flags */ +#define F_SETFL 4 /* set file->f_flags */ +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ + +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* for leases */ +#define F_INPROGRESS 16 + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + +#define F_LINUX_SPECIFIC_BASE 1024 +#endif /* _NIOS2_FCNTL_H */ diff --git a/include/asm-nios2nommu/flat.h b/include/asm-nios2nommu/flat.h new file mode 100644 index 00000000..15050dbf --- /dev/null +++ b/include/asm-nios2nommu/flat.h @@ -0,0 +1,126 @@ +/* + * include/asm-nios2nommu/flat.h -- uClinux bFLT relocations + * + * Copyright (C) 2004,05 Microtronix Datacom Ltd + * + * 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 Wentao Xu + */ + +#ifndef __NIOS2_FLAT_H__ +#define __NIOS2_FLAT_H__ + +#define flat_reloc_valid(reloc, size) ((reloc) <= (size + 0x8000)) + +/* The stack is 64-bit aligned for Nios II, so (sp - 1) shall + * be 64-bit aligned, where -1 is for argc + */ +#define flat_stack_align(sp) (sp = (unsigned long *)(((unsigned long)sp - 1) & (-8))) + +/* The uClibc port for Nios II expects the argc is followed by argv and envp */ +#define flat_argvp_envp_on_stack() 1 + +#define flat_old_ram_flag(flags) (flags) + +/* We store the type of relocation in the top 4 bits of the `relval.' */ + +/* Convert a relocation entry into an address. */ +static inline unsigned long +flat_get_relocate_addr (unsigned long relval) +{ + return relval & 0x0fffffff; /* Mask out top 4-bits */ +} + +#define FLAT_NIOS2_RELOC_TYPE(relval) ((relval) >> 28) + +#define FLAT_NIOS2_R_32 0 /* Normal 32-bit reloc */ +#define FLAT_NIOS2_R_HI_LO 1 /* High 16-bits + low 16-bits field */ +#define FLAT_NIOS2_R_HIADJ_LO 2 /* High 16-bits adjust + low 16-bits field */ +#define FLAT_NIOS2_R_CALL26 4 /* Call imm26 */ + +/* Extract the address to be relocated from the symbol reference at rp; + * relval is the raw relocation-table entry from which RP is derived. + * rp shall always be 32-bit aligned + */ +static inline unsigned long flat_get_addr_from_rp (unsigned long *rp, + unsigned long relval, + unsigned long flags) +{ + switch (FLAT_NIOS2_RELOC_TYPE(relval)) + { + case FLAT_NIOS2_R_32: + /* Simple 32-bit address. The loader expect it in bigger endian */ + return htonl(*rp); + + case FLAT_NIOS2_R_HI_LO: + /* get the two 16-bit immediate value from instructions, then + * construct a 32-bit value. Again the loader expect bigger endian + */ + return htonl ((((rp[0] >> 6) & 0xFFFF) << 16 ) | + ((rp[1] >> 6) & 0xFFFF)); + + case FLAT_NIOS2_R_HIADJ_LO: + { + /* get the two 16-bit immediate value from instructions, then + * construct a 32-bit value. Again the loader expect bigger endian + */ + unsigned int low, high; + high = (rp[0] >> 6) & 0xFFFF; + low = (rp[1] >> 6) & 0xFFFF; + + if ((low >> 15) & 1) high--; + + return htonl ((high << 16 ) | low ); + } + case FLAT_NIOS2_R_CALL26: + /* the 26-bit immediate value is actually 28-bit */ + return htonl(((*rp) >> 6) << 2); + + default: + return ~0; /* bogus value */ + } +} + +/* Insert the address addr into the symbol reference at rp; + * relval is the raw relocation-table entry from which rp is derived. + * rp shall always be 32-bit aligned + */ +static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr, + unsigned long relval) +{ + unsigned long exist_val; + switch (FLAT_NIOS2_RELOC_TYPE (relval)) { + case FLAT_NIOS2_R_32: + /* Simple 32-bit address. */ + *rp = addr; + break; + + case FLAT_NIOS2_R_HI_LO: + exist_val = rp[0]; + rp[0] = ((((exist_val >> 22) << 16) | (addr >> 16)) << 6) | (exist_val & 0x3F); + exist_val = rp[1]; + rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); + break; + + case FLAT_NIOS2_R_HIADJ_LO: + { + unsigned int high = (addr >> 16); + if ((addr >> 15) & 1) + high = (high + 1) & 0xFFFF; + exist_val = rp[0]; + rp[0] = ((((exist_val >> 22) << 16) | high) << 6) | (exist_val & 0x3F); + exist_val = rp[1]; + rp[1] = ((((exist_val >> 22) << 16) | (addr & 0xFFFF)) << 6) | (exist_val & 0x3F); + break; + } + case FLAT_NIOS2_R_CALL26: + /* the opcode of CALL is 0, so just store the value */ + *rp = ((addr >> 2) << 6); + break; + } +} + +#endif /* __NIOS2_FLAT_H__ */ diff --git a/include/asm-nios2nommu/futex.h b/include/asm-nios2nommu/futex.h new file mode 100644 index 00000000..6a332a9f --- /dev/null +++ b/include/asm-nios2nommu/futex.h @@ -0,0 +1,6 @@ +#ifndef _ASM_FUTEX_H +#define _ASM_FUTEX_H + +#include + +#endif diff --git a/include/asm-nios2nommu/gpio.h b/include/asm-nios2nommu/gpio.h new file mode 100644 index 00000000..b91937be --- /dev/null +++ b/include/asm-nios2nommu/gpio.h @@ -0,0 +1,11 @@ +#ifndef _ASM_GPIO_H_ +#define _ASM_GPIO_H_ 1 + + +struct gpio_i2c_pins { + unsigned sda_pin; + unsigned scl_pin; +}; + +#endif /*_ASM_GPIO_*/ + diff --git a/include/asm-nios2nommu/hardirq.h b/include/asm-nios2nommu/hardirq.h new file mode 100644 index 00000000..0041f514 --- /dev/null +++ b/include/asm-nios2nommu/hardirq.h @@ -0,0 +1,43 @@ +/* + * Ported from m68knommu + * + * Copyright (C) 2003, Microtronix Datacom Ltd. + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __NIOS2_HARDIRQ_H +#define __NIOS2_HARDIRQ_H + +#include +#include + +typedef struct { + unsigned int __softirq_pending; +} ____cacheline_aligned irq_cpustat_t; + +#include /* Standard mappings for irq_cpustat_t above */ + +#define HARDIRQ_BITS 8 + +#ifdef CONFIG_SMP +# error nios2nommu SMP is not available +#endif /* CONFIG_SMP */ + +#endif /* __NIOS2_HARDIRQ_H */ diff --git a/include/asm-nios2nommu/hdreg.h b/include/asm-nios2nommu/hdreg.h new file mode 100644 index 00000000..b4d910ac --- /dev/null +++ b/include/asm-nios2nommu/hdreg.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 1994-1996 Linus Torvalds & authors + * Copyright (C) 2002 Wentau Xu (www.microtronix.com) + * copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2_HDREG_H +#define __NIOS2_HDREG_H + +typedef unsigned long ide_ioreg_t; + +#endif /* __NIOS2_HDREG_H */ diff --git a/include/asm-nios2nommu/hw_irq.h b/include/asm-nios2nommu/hw_irq.h new file mode 100644 index 00000000..d2fd3bee --- /dev/null +++ b/include/asm-nios2nommu/hw_irq.h @@ -0,0 +1,16 @@ +#ifndef _ASM_HW_IRQ_H +#define _ASM_HW_IRQ_H + +/* + * linux/include/asm/hw_irq.h + * + * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar + * + * moved some of the old arch/i386/kernel/irq.h to here. VY + * + * IRQ/IPI changes taken from work by Thomas Radke + * + */ + + +#endif /* _ASM_HW_IRQ_H */ diff --git a/include/asm-nios2nommu/ide.h b/include/asm-nios2nommu/ide.h new file mode 100644 index 00000000..dc45674e --- /dev/null +++ b/include/asm-nios2nommu/ide.h @@ -0,0 +1,47 @@ +/* + * linux/include/asm-niosnommu2/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASMNIOS2_IDE_H +#define __ASMNIOS2_IDE_H + +#ifdef __KERNEL__ +#undef MAX_HWIFS /* we're going to force it */ + +#ifndef MAX_HWIFS +#define MAX_HWIFS 1 +#endif + +#define IDE_ARCH_OBSOLETE_INIT +#define IDE_ARCH_OBSOLETE_DEFAULTS +#define ide_default_io_base(i) ((unsigned long)na_ide_ide) +#define ide_default_irq(b) (na_ide_ide_irq) +#define ide_init_default_irq(base) ide_default_irq(base) +#define ide_default_io_ctl(base) ((base) + (0xE*4)) + +#include + +#endif /* __KERNEL__ */ + +#endif /* __ASMNIOS2_IDE_H */ diff --git a/include/asm-nios2nommu/init.h b/include/asm-nios2nommu/init.h new file mode 100644 index 00000000..8641f4f4 --- /dev/null +++ b/include/asm-nios2nommu/init.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#error " should never be used - use instead" diff --git a/include/asm-nios2nommu/io.h b/include/asm-nios2nommu/io.h new file mode 100644 index 00000000..73a5c176 --- /dev/null +++ b/include/asm-nios2nommu/io.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2_IO_H +#define __NIOS2_IO_H + +#ifdef __KERNEL__ + +#include + +#include /* IO address mapping routines need this */ +#include +#include + +extern void insw(unsigned long port, void *dst, unsigned long count); +extern void outsw(unsigned long port, void *src, unsigned long count); +extern void insl(unsigned long port, void *dst, unsigned long count); +extern void outsl(unsigned long port, void *src, unsigned long count); + +#define readsb(p,d,l) insb(p,d,l) +#define readsw(p,d,l) insw(p,d,l) +#define readsl(p,d,l) insl(p,d,l) +#define writesb(p,d,l) outsb(p,d,l) +#define writesw(p,d,l) outsw(p,d,l) +#define writesl(p,d,l) outsl(p,d,l) +#ifndef irq_canonicalize +#define irq_canonicalize(i) (i) +#endif + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the Nios architecture, we just read/write the + * memory location directly. + */ + +#define readb(addr) \ +({ \ + unsigned char __res;\ + __asm__ __volatile__( \ + "ldbuio %0, 0(%1)" \ + : "=r"(__res) \ + : "r" (addr)); \ + __res; \ +}) + +#define readw(addr) \ +({ \ + unsigned short __res;\ + __asm__ __volatile__( \ + "ldhuio %0, 0(%1)" \ + : "=r"(__res) \ + : "r" (addr)); \ + __res; \ +}) + +#define readl(addr) \ +({ \ + unsigned int __res;\ + __asm__ __volatile__( \ + "ldwio %0, 0(%1)" \ + : "=r"(__res) \ + : "r" (addr)); \ + __res; \ +}) + +#define writeb(b,addr) \ +({ \ + __asm__ __volatile__( \ + "stbio %0, 0(%1)" \ + : : "r"(b), "r" (addr)); \ +}) + +#define writew(b,addr) \ +({ \ + __asm__ __volatile__( \ + "sthio %0, 0(%1)" \ + : : "r"(b), "r" (addr)); \ +}) + +#define writel(b,addr) \ +({ \ + __asm__ __volatile__( \ + "stwio %0, 0(%1)" \ + : : "r"(b), "r" (addr)); \ +}) + +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +#define mmiowb() + +/* + * make the short names macros so specific devices + * can override them as required + */ + +#define memset_io(addr,c,len) memset((void *)(((unsigned int)(addr)) | 0x80000000),(c),(len)) +#define memcpy_fromio(to,from,len) memcpy((to),(void *)(((unsigned int)(from)) | 0x80000000),(len)) +#define memcpy_toio(to,from,len) memcpy((void *)(((unsigned int)(to)) | 0x80000000),(from),(len)) + +#define inb(addr) readb(addr) +#define inw(addr) readw(addr) +#define inl(addr) readl(addr) + +#define outb(x,addr) ((void) writeb(x,addr)) +#define outw(x,addr) ((void) writew(x,addr)) +#define outl(x,addr) ((void) writel(x,addr)) + +#define inb_p(addr) inb(addr) +#define inw_p(addr) inw(addr) +#define inl_p(addr) inl(addr) + +#define outb_p(x,addr) outb(x,addr) +#define outw_p(x,addr) outw(x,addr) +#define outl_p(x,addr) outl(x,addr) + + + +extern inline void insb(unsigned long port, void *dst, unsigned long count) +{ + unsigned char *p=(unsigned char*)dst; + while (count--) + *p++ = inb(port); +} + +/* See arch/niosnommu/io.c for optimized version */ +extern inline void _insw(unsigned long port, void *dst, unsigned long count) +{ + unsigned short *p=(unsigned short*)dst; + while (count--) + *p++ = inw(port); +} + +/* See arch/niosnommu/kernel/io.c for unaligned destination pointer */ +extern inline void _insl(unsigned long port, void *dst, unsigned long count) +{ + unsigned long *p=(unsigned long*)dst; + while (count--) + *p++ = inl(port); +} + +extern inline void outsb(unsigned long port, void *src, unsigned long count) +{ + unsigned char *p=(unsigned char*)src; + while (count--) + outb( *p++, port ); +} + +/* See arch/niosnommu/io.c for optimized version */ +extern inline void _outsw(unsigned long port, void *src, unsigned long count) +{ + unsigned short *p=(unsigned short*)src; + while (count--) + outw( *p++, port ); +} + +/* See arch/niosnommu/kernel/io.c for unaligned source pointer */ +extern inline void _outsl(unsigned long port, void *src, unsigned long count) +{ + unsigned long *p=(unsigned long*)src; + while (count--) + outl( *p++, port ); +} + + + +extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr, + int bus, int rdonly) +{ + return; +} + +//vic - copied from m68knommu + +/* Values for nocacheflag and cmode */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_WRITETHROUGH 3 + +extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); +extern void __iounmap(void *addr, unsigned long size); + +extern inline void *ioremap(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +extern inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); +} +extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_FULL_CACHING); +} + +extern void iounmap(void *addr); + + +#define IO_SPACE_LIMIT 0xffffffff + +#define dma_cache_inv(_start,_size) dcache_push(_start,_size) +#define dma_cache_wback(_start,_size) dcache_push(_start,_size) +#define dma_cache_wback_inv(_start,_size) dcache_push(_start,_size) + +/* Pages to physical address... */ +#define page_to_phys(page) page_to_virt(page) +#define page_to_bus(page) page_to_virt(page) + +#define mm_ptov(vaddr) ((void *) (vaddr)) +#define mm_vtop(vaddr) ((unsigned long) (vaddr)) +#define phys_to_virt(vaddr) ((void *) (vaddr)) +#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem + * access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#endif /* __KERNEL__ */ + +#endif /* !(__NIOS2_IO_H) */ + diff --git a/include/asm-nios2nommu/ioctl.h b/include/asm-nios2nommu/ioctl.h new file mode 100644 index 00000000..c02a36af --- /dev/null +++ b/include/asm-nios2nommu/ioctl.h @@ -0,0 +1,100 @@ +/* $Id: ioctl.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ + * + * linux/ioctl.h for Linux by H.H. Bergman. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2_IOCTL_H +#define _NIOS2_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * I don't really have any idea about what this should look like, so + * for the time being, this is heavily based on the PC definitions. + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _NIOS2_IOCTL_H */ diff --git a/include/asm-nios2nommu/ioctls.h b/include/asm-nios2nommu/ioctls.h new file mode 100644 index 00000000..288025c7 --- /dev/null +++ b/include/asm-nios2nommu/ioctls.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ARCH_NIOS2_IOCTLS_H__ +#define __ARCH_NIOS2_IOCTLS_H__ + +#include + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __ARCH_NIOS2_IOCTLS_H__ */ diff --git a/include/asm-nios2nommu/ipc.h b/include/asm-nios2nommu/ipc.h new file mode 100644 index 00000000..cb86a316 --- /dev/null +++ b/include/asm-nios2nommu/ipc.h @@ -0,0 +1,51 @@ +#ifndef __NIOS2_IPC_H__ +#define __NIOS2_IPC_H__ + +/* Copied from sparc version + * These are used to wrap system calls on the Nios. + * + * See arch/niosnommu/kernel/sys_nios.c for ugly details.. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +/* Used by the DIPC package, try and avoid reusing it */ +#define DIPC 25 + +#define IPCCALL(version,op) ((version)<<16 | (op)) + +#endif diff --git a/include/asm-nios2nommu/ipcbuf.h b/include/asm-nios2nommu/ipcbuf.h new file mode 100644 index 00000000..ef595333 --- /dev/null +++ b/include/asm-nios2nommu/ipcbuf.h @@ -0,0 +1,49 @@ +#ifndef __NIOS2_IPCBUF_H__ +#define __NIOS2_IPCBUF_H__ + +/* Copied from asm-m68k/ipcbuf.h + * The user_ipc_perm structure for Nios architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __NIOS2_IPCBUF_H__ */ diff --git a/include/asm-nios2nommu/irq.h b/include/asm-nios2nommu/irq.h new file mode 100644 index 00000000..f0e37a24 --- /dev/null +++ b/include/asm-nios2nommu/irq.h @@ -0,0 +1,181 @@ +/* + * 21Mar2001 1.1 dgt/microtronix + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef _NIOS2NOMMU_IRQ_H_ +#define _NIOS2NOMMU_IRQ_H_ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +#include + +#define SYS_IRQS 32 +#define NR_IRQS SYS_IRQS + +/* + * Interrupt source definitions + * General interrupt sources are the level 1-7. + * Adding an interrupt service routine for one of these sources + * results in the addition of that routine to a chain of routines. + * Each one is called in succession. Each individual interrupt + * service routine should determine if the device associated with + * that routine requires service. + */ + +#define IRQ01 (1) /* level 1 interrupt */ +#define IRQ02 (2) /* level 2 interrupt */ +#define IRQ03 (3) /* level 3 interrupt */ +#define IRQ04 (4) /* level 4 interrupt */ +#define IRQ05 (5) /* level 5 interrupt */ +#define IRQ06 (6) /* level 6 interrupt */ +#define IRQ07 (7) /* level 7 interrupt */ +#define IRQ08 (8) /* level 8 interrupt */ +#define IRQ09 (9) /* level 9 interrupt */ +#define IRQ0A (10) /* level 10 interrupt */ +#define IRQ0B (11) /* level 11 interrupt */ +#define IRQ0C (12) /* level 12 interrupt */ +#define IRQ0D (13) /* level 13 interrupt */ +#define IRQ0E (14) /* level 14 interrupt */ +#define IRQ0F (15) /* level 15 interrupt */ +#define IRQ10 (16) /* level 16 interrupt */ +#define IRQ12 (17) /* level 17 interrupt */ +#define IRQ13 (18) /* level 18 interrupt */ +#define IRQ14 (19) /* level 19 interrupt */ +#define IRQ15 (20) /* level 20 interrupt */ +#define IRQ16 (21) /* level 21 interrupt */ +#define IRQ17 (22) /* level 22 interrupt */ +#define IRQ18 (23) /* level 23 interrupt */ +#define IRQ19 (24) /* level 24 interrupt */ +#define IRQ1A (25) /* level 25 interrupt */ +#define IRQ1B (26) /* level 26 interrupt */ +#define IRQ1C (27) /* level 27 interrupt */ +#define IRQ1D (28) /* level 28 interrupt */ +#define IRQ1E (29) /* level 29 interrupt */ +#define IRQ1F (30) /* level 30 interrupt */ +#define IRQ20 (31) /* level 31 interrupt */ +#define IRQ21 (32) /* level 32 interrupt */ + +#define IRQMAX IRQ21 + +/* + * "Generic" interrupt sources + */ + +/* + * Machine specific interrupt sources. + * + * Adding an interrupt service routine for a source with this bit + * set indicates a special machine specific interrupt source. + * The machine specific files define these sources. + * + * Removed, they are not used by any one. + */ + +/* + * various flags for request_irq() + */ +#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */ +#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */ +#define IRQ_FLG_FAST (0x0004) +#define IRQ_FLG_SLOW (0x0008) +#define IRQ_FLG_STD (0x8000) /* internally used */ + +/* + * Functions to set and clear the interrupt mask. + */ + +/* + * Use a zero to clean the bit. + */ +static inline void clrimr(int mask) +{ + int flags; + + local_irq_save(flags); + __asm__ __volatile__( + "rdctl r8, ienable\n" + "and r8,r8,%0\n" + "wrctl ienable, r8\n" + : /* No output */ + : "r" (mask) + : "r8"); + local_irq_restore(flags); +} + +/* + * Use a one to set the bit. + */ +static inline void setimr(int mask) +{ + int flags; + + local_irq_save(flags); + __asm__ __volatile__( + "rdctl r8, ienable\n" + "or r8,r8,%0\n" + "wrctl ienable, r8\n" + : /* No output */ + : "r" (mask) + : "r8"); + local_irq_restore(flags); +} + +/* + * This structure is used to chain together the ISRs for a particular + * interrupt source (if it supports chaining). + */ +typedef struct irq_node { + irq_handler_t handler; + unsigned long flags; + void *dev_id; + const char *devname; + struct irq_node *next; +} irq_node_t; + +/* + * This function returns a new irq_node_t + */ +extern irq_node_t *new_irq_node(void); + +/* + * This structure has only 4 elements for speed reasons + */ +typedef struct irq_hand { + irq_handler_t handler; + unsigned long flags; + void *dev_id; + const char *devname; +} irq_hand_t; + +/* count of spurious interrupts */ +extern volatile unsigned int num_spurious; + +#define disable_irq_nosync(i) disable_irq(i) + +#ifndef irq_canonicalize +#define irq_canonicalize(i) (i) +#endif + +#endif /* _NIOS2NOMMU_IRQ_H_ */ diff --git a/include/asm-nios2nommu/irq_node.h b/include/asm-nios2nommu/irq_node.h new file mode 100644 index 00000000..24f9763f --- /dev/null +++ b/include/asm-nios2nommu/irq_node.h @@ -0,0 +1,36 @@ +#ifndef _NIOS2NOMMU_IRQNODE_H_ +#define _NIOS2NOMMU_IRQNODE_H_ + +#include + +/* + * This structure is used to chain together the ISRs for a particular + * interrupt source (if it supports chaining). + */ +typedef struct irq_node { + irqreturn_t (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + struct irq_node *next; +} irq_node_t; + +/* + * This structure has only 4 elements for speed reasons + */ +typedef struct irq_handler { + irqreturn_t (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; +} irq_handler_t; + +/* count of spurious interrupts */ +extern volatile unsigned int num_spurious; + +/* + * This function returns a new irq_node_t + */ +extern irq_node_t *new_irq_node(void); + +#endif /* _NIOS2NOMMU_IRQNODE_H_ */ diff --git a/include/asm-nios2nommu/irq_regs.h b/include/asm-nios2nommu/irq_regs.h new file mode 100644 index 00000000..3dd9c0b7 --- /dev/null +++ b/include/asm-nios2nommu/irq_regs.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-nios2nommu/kmap_types.h b/include/asm-nios2nommu/kmap_types.h new file mode 100644 index 00000000..a26b91d5 --- /dev/null +++ b/include/asm-nios2nommu/kmap_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#endif diff --git a/include/asm-nios2nommu/linkage.h b/include/asm-nios2nommu/linkage.h new file mode 100644 index 00000000..db792970 --- /dev/null +++ b/include/asm-nios2nommu/linkage.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .align 3 +#define __ALIGN_STR ".align 3" + +#endif diff --git a/include/asm-nios2nommu/linux_logo.h b/include/asm-nios2nommu/linux_logo.h new file mode 100644 index 00000000..f9d38e7a --- /dev/null +++ b/include/asm-nios2nommu/linux_logo.h @@ -0,0 +1,953 @@ +/* $Id: linux_logo.h,v 1.1 2006/07/05 06:20:25 gerg Exp $ + * include/asm-nios/linux_logo.h: This is a linux logo + * to be displayed on boot. + * + * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu) + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2004 Micrtronix Datacom Ltd. + * + * You can put anything here, but: + * LINUX_LOGO_COLORS has to be less than 224 + * image size has to be 80x80 + * values have to start from 0x20 + * (i.e. RGB(linux_logo_red[0], + * linux_logo_green[0], + * linux_logo_blue[0]) is color 0x20) + * BW image has to be 80x80 as well, with MS bit + * on the left + * Serial_console ascii image can be any size, + * but should contain %s to display the version + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#define linux_logo_banner "Linux/NIOS2 version " UTS_RELEASE + +#define __HAVE_ARCH_LINUX_LOGO +#define __HAVE_ARCH_LINUX_LOGO16 + +#define LINUX_LOGO_COLORS 221 + +#ifdef INCLUDE_LINUX_LOGO_DATA + +unsigned char linux_logo_red[] __initdata = { + 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, + 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, + 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, + 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, + 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, + 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, + 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, + 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, + 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, + 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, + 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, + 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, + 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, + 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, + 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, + 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfe, + 0xf6, 0xec, 0xfe, 0xd2, 0xea, 0xf5, 0xf2, 0xf2, + 0xe9, 0xee, 0xf6, 0xf2, 0xee, 0xf6, 0xda, 0xd4, + 0xfa, 0xca, 0xf2, 0xf6, 0xfe, 0xf2, 0xda, 0xe4, + 0xf6, 0xdd, 0xf2, 0xee, 0xfa, 0xf0, 0x12, 0x4a, + 0xd6, 0xf2, 0x8e, 0xf2, 0xf6, 0xf6, 0xb5, 0xf1, + 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, 0x9a, + 0x2e, 0xd2, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, + 0xda, 0xee, 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xe0, + 0xae, 0xbe, 0xce, 0xe2, 0xa3, 0x8e, 0x6d, 0x8e, + 0x32, 0xaf, 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, + 0x7a, 0x82, 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, + 0x6a, 0x52, 0x59, 0x64, 0x5e, +}; + +unsigned char linux_logo_green[] __initdata = { + 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, + 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, + 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, + 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, + 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, + 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, + 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, + 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, + 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, + 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, + 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, + 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, + 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, + 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, + 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, + 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xfa, + 0xea, 0xd7, 0xf6, 0xbc, 0xda, 0xde, 0xda, 0xe6, + 0xca, 0xd8, 0xea, 0xe0, 0xcc, 0xf2, 0xce, 0xb2, + 0xee, 0xa2, 0xd6, 0xe6, 0xf6, 0xd7, 0xc5, 0xb8, + 0xc6, 0xb9, 0xce, 0xde, 0xce, 0xc6, 0x0e, 0x36, + 0xae, 0xbe, 0x86, 0xba, 0xbe, 0xe6, 0x8e, 0xc4, + 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, 0x7a, + 0x20, 0xc6, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, + 0xce, 0xd6, 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa6, + 0x87, 0x96, 0xa2, 0xd6, 0x85, 0x7a, 0x6a, 0x6e, + 0x22, 0x76, 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, + 0x66, 0x62, 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, + 0x56, 0x3e, 0x51, 0x52, 0x56, +}; + +unsigned char linux_logo_blue[] __initdata = { + 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, + 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, + 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, + 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, + 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, + 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, + 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, + 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, + 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, + 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, + 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, + 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, + 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, + 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, + 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, + 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0xea, + 0xb6, 0x7c, 0xda, 0x8e, 0xa6, 0x87, 0x66, 0xb6, + 0x81, 0x6a, 0xc6, 0x9a, 0x5b, 0xd2, 0xb6, 0x6a, + 0xca, 0x45, 0x92, 0xb2, 0xca, 0x52, 0x8a, 0x3e, + 0x2e, 0x66, 0x66, 0xae, 0x3e, 0x47, 0x06, 0x0e, + 0x52, 0x36, 0x6a, 0x0e, 0x0e, 0xbe, 0x2c, 0x0e, + 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, 0x2e, + 0x06, 0x9e, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, + 0x9e, 0xae, 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x0a, + 0x32, 0x2e, 0x2a, 0xb2, 0x43, 0x48, 0x5f, 0x2e, + 0x06, 0x06, 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, + 0x46, 0x2e, 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, + 0x3a, 0x22, 0x42, 0x34, 0x42, +}; + +unsigned char linux_logo[] __initdata = { + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, + 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, + 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, + 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, + 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, + 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, + 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, + 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, + 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, + 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, + 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, + 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, + 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, + 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, + 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, + 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, + 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, + 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, + 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, + 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, + 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, + 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, + 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, + 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, + 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, + 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, + 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, + 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, + 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, + 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, + 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, + 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, + 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, + 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, + 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, + 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, + 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, + 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, + 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, + 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, + 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, + 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, + 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, + 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, + 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, + 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, + 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, + 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, + 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, + 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, + 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, + 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, + 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, + 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, + 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, + 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, + 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, + 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, + 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, + 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, + 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, + 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, + 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, + 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, + 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, + 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, + 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, + 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, + 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, + 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, + 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, + 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, + 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, + 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, + 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, + 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, + 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, + 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, + 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, + 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, + 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, + 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, + 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, + 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, + 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, + 0x48, 0x48, 0x48, 0x9b, 0x99, 0x9f, 0x52, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, + 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, + 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, + 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, + 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, + 0x47, 0x9f, 0x48, 0x48, 0x48, 0xa0, 0xa1, 0xa2, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, + 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, + 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, + 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, + 0xa3, 0xa4, 0x48, 0x48, 0x9f, 0xa5, 0xa6, 0x9f, + 0x48, 0x48, 0x48, 0xa2, 0xa7, 0x47, 0x48, 0x48, + 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, + 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, + 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, + 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, + 0xa8, 0xa1, 0x48, 0x48, 0x9f, 0xa9, 0xa6, 0x9f, + 0x48, 0x48, 0xaa, 0xa1, 0xa5, 0x9f, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, + 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, + 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, + 0x36, 0x24, 0x4f, 0x48, 0x52, 0x52, 0x48, 0x48, + 0xab, 0xac, 0xa0, 0x48, 0xad, 0xa6, 0xa6, 0x9f, + 0x48, 0xa2, 0xa9, 0xa6, 0xa2, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, + 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, + 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, + 0x36, 0x3a, 0x48, 0x48, 0xae, 0xaf, 0x48, 0x48, + 0xad, 0xac, 0xa1, 0x9f, 0xa2, 0xa9, 0xa9, 0xa2, + 0x48, 0xab, 0x78, 0xa7, 0x48, 0x48, 0x48, 0x48, + 0x9f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, + 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, + 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, + 0x23, 0x43, 0x48, 0x48, 0xb0, 0xb1, 0xb2, 0x9f, + 0x48, 0xb3, 0xa5, 0xb3, 0xab, 0xa9, 0xa9, 0xb3, + 0xb4, 0xa9, 0xb5, 0xb0, 0x48, 0x48, 0xa0, 0xa5, + 0xa1, 0xad, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, + 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, + 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, + 0x2e, 0x9b, 0x48, 0x48, 0x48, 0xb6, 0xb7, 0xa4, + 0xa2, 0xa7, 0xb5, 0x78, 0x6f, 0x6f, 0x6e, 0x6f, + 0xa9, 0xb5, 0xab, 0x48, 0x9f, 0xab, 0xa9, 0xa1, + 0xaa, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, + 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, + 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, + 0x54, 0x48, 0x48, 0x48, 0x48, 0xa2, 0xa8, 0xa1, + 0xa5, 0xa6, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x78, 0xa5, 0xa0, 0xa0, 0x78, 0xa6, 0xa2, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, + 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, + 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, + 0x43, 0x48, 0x4b, 0xa2, 0x9f, 0x48, 0xa2, 0xa1, + 0xb8, 0x6e, 0x6e, 0xb5, 0x78, 0x6f, 0x78, 0x78, + 0x6e, 0x6f, 0x78, 0xb5, 0xa6, 0xa1, 0xa0, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, + 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, + 0x52, 0x48, 0xa3, 0xb1, 0xb6, 0xb3, 0xaa, 0xac, + 0x68, 0x68, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x78, 0x6f, 0x6f, 0xb5, 0xa6, 0xb4, 0x48, 0x9f, + 0xb4, 0xb4, 0xa2, 0x9f, 0x48, 0x48, 0x4f, 0x21, + 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, + 0x47, 0x48, 0xa2, 0xb6, 0xaf, 0xb9, 0xba, 0x68, + 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x78, + 0x6f, 0x6f, 0xa6, 0x6f, 0xb5, 0xa0, 0xaa, 0xa6, + 0xa6, 0xa9, 0xb2, 0xb3, 0x48, 0x48, 0x4c, 0x22, + 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, + 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, + 0x9b, 0x48, 0x48, 0x48, 0xb0, 0xb0, 0xba, 0xb8, + 0x68, 0x68, 0x69, 0x78, 0x6f, 0xb5, 0x6f, 0xb5, + 0x78, 0x78, 0x78, 0x78, 0x78, 0xa5, 0xbb, 0xa9, + 0xa5, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, + 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, + 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, + 0x9b, 0x48, 0x48, 0x48, 0x48, 0x9f, 0xac, 0x68, + 0xbc, 0x6e, 0x6e, 0x6e, 0xb5, 0x6f, 0x6e, 0x6f, + 0x6f, 0x78, 0x78, 0xb5, 0xb5, 0xa5, 0x9f, 0x9f, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, + 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, + 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, + 0x9b, 0x48, 0x48, 0xb0, 0xaa, 0xb3, 0xbd, 0xb8, + 0xb8, 0x68, 0x6e, 0x6e, 0xb5, 0x6f, 0x78, 0x6e, + 0x78, 0x6f, 0x78, 0x78, 0xb5, 0xa9, 0xa2, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, + 0x24, 0x27, 0xbe, 0x24, 0x25, 0x28, 0x21, 0x36, + 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, + 0x39, 0x4d, 0xbf, 0x84, 0x81, 0x57, 0x21, 0x39, + 0x52, 0x48, 0x48, 0x62, 0xb1, 0xc0, 0xc1, 0xc1, + 0xb8, 0xb8, 0x68, 0xbc, 0x6e, 0x6e, 0x6e, 0x78, + 0x78, 0x78, 0x78, 0x6e, 0x78, 0xa9, 0xa0, 0xab, + 0xb3, 0xa2, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, + 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, + 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, + 0x2d, 0xc2, 0x7a, 0xc3, 0xc4, 0xc4, 0x7f, 0x22, + 0x51, 0x52, 0x48, 0x48, 0xb0, 0xaa, 0xa8, 0xbd, + 0x68, 0xb8, 0xb8, 0x68, 0x68, 0x6e, 0x6e, 0x6f, + 0x6e, 0x6e, 0xb5, 0x6e, 0x78, 0xab, 0xab, 0xb5, + 0x78, 0xa6, 0xb3, 0xc5, 0xac, 0xac, 0xc6, 0x61, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, + 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, + 0x4d, 0x91, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0x5a, + 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0xb0, 0x64, + 0xc1, 0xb8, 0xb8, 0xb8, 0x68, 0x71, 0x6e, 0x6e, + 0x6f, 0x71, 0x6f, 0x6f, 0xa6, 0xa0, 0x9f, 0xb4, + 0xb4, 0xa0, 0xa1, 0xb7, 0xc7, 0x69, 0x66, 0xc8, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, + 0x83, 0xc9, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, + 0x60, 0x85, 0xca, 0xcb, 0xc4, 0xc4, 0xc4, 0x82, + 0x86, 0x36, 0x32, 0x3f, 0xa2, 0xa4, 0xa8, 0xa9, + 0xb8, 0xb8, 0xb8, 0xb8, 0x68, 0x6e, 0x6e, 0x6e, + 0x6e, 0x71, 0x6f, 0x71, 0xa6, 0xb4, 0x9f, 0x9f, + 0x48, 0x48, 0x48, 0xcc, 0xc3, 0xc7, 0xcd, 0xce, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, + 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x23, 0x30, 0x31, 0xcf, 0x91, 0x7e, 0x90, 0x90, + 0x8b, 0x5b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0x5d, 0xd0, 0x36, 0x24, 0xd1, 0xb1, 0xaf, 0xaa, + 0xba, 0xb8, 0x68, 0x68, 0x68, 0x71, 0x6e, 0x6e, + 0x6e, 0x6f, 0x6e, 0x78, 0xa1, 0xa9, 0xa1, 0xb0, + 0x9f, 0x9b, 0x99, 0xcc, 0x64, 0x5c, 0x8b, 0xd0, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, + 0x82, 0x5c, 0xd2, 0x2a, 0x23, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x24, 0x2b, 0xcf, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, + 0x7b, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc7, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, + 0xa2, 0xa8, 0xb7, 0xc1, 0xb8, 0x68, 0x68, 0xbc, + 0x68, 0x6e, 0xb5, 0xb4, 0xb4, 0xab, 0xb5, 0xa1, + 0xb0, 0x4f, 0x3f, 0xd3, 0x7b, 0x7b, 0x85, 0x80, + 0xbe, 0x36, 0x36, 0x36, 0x21, 0xd4, 0x7e, 0x7b, + 0x64, 0x64, 0xd5, 0x35, 0x24, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x26, 0x31, 0xd6, 0x5b, 0x64, 0xc3, 0xc3, 0xcb, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0x66, 0xd7, 0x36, 0x36, 0x36, 0x2c, 0x4b, + 0xd8, 0xd9, 0xb3, 0xa8, 0xbd, 0xbd, 0xbd, 0xbd, + 0xa9, 0xab, 0xb3, 0xa5, 0xa2, 0x9f, 0xa2, 0xa1, + 0x6a, 0x9a, 0x3f, 0xda, 0x76, 0x76, 0x7a, 0x63, + 0xdb, 0xdc, 0x86, 0xdc, 0xdd, 0x90, 0x5b, 0x64, + 0xc3, 0xc3, 0xde, 0x2d, 0x27, 0x23, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc7, 0x83, 0xce, 0x36, 0x36, 0x36, 0x30, + 0xb1, 0xd9, 0x48, 0xa1, 0xb2, 0xb0, 0xb0, 0xb3, + 0xa2, 0x48, 0xa7, 0xbd, 0xa9, 0xa2, 0x48, 0x9f, + 0xaa, 0x9a, 0x3f, 0xb1, 0x5b, 0x7b, 0xdf, 0x85, + 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xc3, 0xc4, + 0xc4, 0xcb, 0x5d, 0xd5, 0x39, 0x26, 0x23, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x26, 0x2d, 0xe0, 0xdf, 0x64, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc7, 0x88, 0x36, 0x36, 0x36, 0x36, + 0x2d, 0x9b, 0x48, 0xb9, 0xaf, 0xa2, 0xa2, 0xb9, + 0xa8, 0x9f, 0x48, 0xa7, 0xb7, 0xd9, 0x48, 0x48, + 0x9b, 0x45, 0x3f, 0xe1, 0x6d, 0x7b, 0xca, 0xdf, + 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc3, 0xe2, 0x37, 0x35, 0x26, 0x23, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x26, 0x2e, 0xe0, 0x7a, 0x7b, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc7, 0x72, 0x73, 0x36, 0x36, 0x36, + 0x24, 0x52, 0x48, 0xa3, 0xaf, 0x9f, 0x48, 0xb6, + 0xaf, 0xa2, 0x48, 0x9f, 0xe3, 0xd8, 0x48, 0x48, + 0x48, 0x46, 0x42, 0xd6, 0x7a, 0x7b, 0x64, 0x7b, + 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xc3, 0xc4, 0xc4, + 0xc4, 0xc4, 0xcb, 0x64, 0xe2, 0x4d, 0x2c, 0x27, + 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x25, 0x31, 0xe4, 0x8b, 0x7b, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc7, 0x89, 0xbe, 0x36, 0x36, + 0x32, 0x47, 0x48, 0x4f, 0xa0, 0x48, 0x48, 0xe3, + 0x92, 0x9f, 0x48, 0x9f, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xc3, 0xcb, + 0xc3, 0x64, 0x64, 0xc3, 0xc3, 0xcb, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x5d, 0xe5, 0x2c, + 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x25, 0x31, 0xe4, 0x85, 0x7b, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x57, 0x27, 0x4d, + 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x99, 0x34, 0xbe, 0xdb, 0x7a, 0x7b, 0xc3, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xe4, + 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x26, 0x2d, 0xe4, 0x85, 0x7b, 0xcb, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc7, 0x5f, 0x92, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, + 0x35, 0x36, 0xce, 0xdd, 0x7a, 0x7b, 0xcb, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0xc3, 0xe1, + 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, + 0x30, 0x2f, 0xd6, 0x8b, 0x7b, 0xcb, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x66, 0x89, 0x45, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, + 0x36, 0x36, 0x61, 0xdb, 0x6d, 0x64, 0xcb, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0xdf, 0xe5, + 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, + 0x33, 0xe6, 0x63, 0xdf, 0xc3, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x72, 0x81, 0xe7, + 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, + 0x36, 0x36, 0xe8, 0x8f, 0x6d, 0x64, 0xcb, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xca, 0x8b, 0xcf, 0x2c, + 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, + 0x35, 0x96, 0x75, 0xca, 0xc3, 0xcb, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x7b, 0x81, 0xdb, + 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, + 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x73, 0xdb, 0x7a, 0x7b, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0x64, 0x76, 0x7a, 0x91, 0xd5, 0x31, 0x30, + 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, + 0x39, 0x97, 0x75, 0xdf, 0x7b, 0x64, 0xc3, 0xc3, + 0xcb, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0x7b, 0x7a, 0xe9, + 0xea, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, + 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x21, 0xea, 0xdd, 0x8b, 0x7b, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0x64, 0x64, + 0x76, 0x85, 0xe0, 0xd5, 0x34, 0x2b, 0x27, 0x28, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, + 0x33, 0xeb, 0x63, 0x7e, 0x7a, 0x6d, 0xdf, 0x5b, + 0x76, 0x7b, 0x64, 0x64, 0xc3, 0xcb, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xcb, 0x76, 0x85, 0xdb, + 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x21, 0xec, 0xdd, 0x75, 0x76, 0xc3, 0xc4, + 0xc4, 0xc4, 0xcb, 0xc3, 0x64, 0x76, 0xdf, 0x8b, + 0xd6, 0xd5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, + 0x27, 0x31, 0xed, 0xeb, 0xdd, 0x74, 0x63, 0x90, + 0x7e, 0x75, 0x8b, 0x6d, 0xdf, 0x76, 0x64, 0xc3, + 0xcb, 0xcb, 0xcb, 0xcb, 0x64, 0x7a, 0x84, 0xee, + 0x79, 0xbe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x21, 0xea, 0xee, 0x63, 0x6d, 0x7b, 0x64, + 0xcb, 0xc3, 0x64, 0x7b, 0xdf, 0x75, 0x63, 0x96, + 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x28, 0x27, 0x35, 0x2d, 0x41, 0xd5, 0xe7, 0x8f, + 0xdb, 0xdd, 0xe9, 0x74, 0x84, 0x90, 0x85, 0x6d, + 0x5b, 0x7b, 0x7b, 0xca, 0x6d, 0x90, 0xdb, 0xef, + 0xec, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, + 0x36, 0x21, 0xd4, 0x80, 0xe9, 0x7e, 0x6d, 0x76, + 0xca, 0x76, 0x6d, 0x85, 0x63, 0xdb, 0xd5, 0x34, + 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, + 0x41, 0xf0, 0xf1, 0x6c, 0x80, 0xee, 0xdb, 0x74, + 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xef, 0x79, + 0xe8, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, + 0x4d, 0x37, 0xf2, 0xf3, 0x8f, 0x74, 0x63, 0x7e, + 0x75, 0x7e, 0x63, 0xe9, 0x88, 0xe6, 0x31, 0x2a, + 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, + 0x33, 0x39, 0x2e, 0x51, 0x41, 0xd2, 0x6c, 0xf3, + 0x80, 0xee, 0xee, 0xee, 0xf4, 0xf3, 0xd7, 0xf5, + 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, + 0x2b, 0x34, 0xf6, 0xec, 0xf7, 0x8f, 0xdd, 0xe9, + 0xe9, 0xdd, 0xee, 0x6c, 0x41, 0x39, 0x27, 0x28, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, + 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, + 0xf8, 0xd7, 0x79, 0x79, 0x79, 0xec, 0xf9, 0x51, + 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, + 0x24, 0x2a, 0x31, 0xfa, 0xea, 0x79, 0xf3, 0x80, + 0xf7, 0xdc, 0xfb, 0x2f, 0x35, 0x26, 0x23, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, + 0x31, 0x2f, 0xf6, 0xfa, 0xfa, 0x2f, 0x2e, 0x33, + 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x21, 0x28, 0x27, 0x35, 0x34, 0xfa, 0xfa, 0xfa, + 0xfc, 0xf6, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, + 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, + 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, + 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, + 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +}; + +unsigned char linux_logo16[1]; + +#endif /* INCLUDE_LINUX_LOGO_DATA */ + +#include + diff --git a/include/asm-nios2nommu/local.h b/include/asm-nios2nommu/local.h new file mode 100644 index 00000000..5ed7d1cc --- /dev/null +++ b/include/asm-nios2nommu/local.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2NOMMU_LOCAL_H +#define __NIOS2NOMMU_LOCAL_H + +#include + +#endif /* __NIOS2NOMMU_LOCAL_H */ diff --git a/include/asm-nios2nommu/mc146818rtc.h b/include/asm-nios2nommu/mc146818rtc.h new file mode 100644 index 00000000..3492fc09 --- /dev/null +++ b/include/asm-nios2nommu/mc146818rtc.h @@ -0,0 +1,29 @@ +/* + * Machine dependent access functions for RTC registers. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _NIOS2_MC146818RTC_H +#define _NIOS2_MC146818RTC_H + +/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ + +#endif /* _NIOS2_MC146818RTC_H */ diff --git a/include/asm-nios2nommu/mman.h b/include/asm-nios2nommu/mman.h new file mode 100644 index 00000000..516ab26a --- /dev/null +++ b/include/asm-nios2nommu/mman.h @@ -0,0 +1,68 @@ +/* + * Copied from the m68k port. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2_MMAN_H__ +#define __NIOS2_MMAN_H__ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_SEM 0x8 /* page may be used for atomic ops */ +#define PROT_NONE 0x0 /* page can not be accessed */ +#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ +#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#define MADV_NORMAL 0x0 /* default page-in behavior */ +#define MADV_RANDOM 0x1 /* page-in minimum required */ +#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ +#define MADV_WILLNEED 0x3 /* pre-fault pages */ +#define MADV_DONTNEED 0x4 /* discard these pages */ + +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + +#endif /* __NIOS2_MMAN_H__ */ + diff --git a/include/asm-nios2nommu/mmu.h b/include/asm-nios2nommu/mmu.h new file mode 100644 index 00000000..b6e579df --- /dev/null +++ b/include/asm-nios2nommu/mmu.h @@ -0,0 +1,36 @@ +/* + * + * Taken from the m68knommu. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2NOMMU_MMU_H +#define __NIOS2NOMMU_MMU_H + +/* Copyright (C) 2002, David McCullough */ + +typedef struct { + struct vm_list_struct *vmlist; + unsigned long end_brk; +} mm_context_t; + +#endif /* __NIOS2NOMMU_MMU_H */ diff --git a/include/asm-nios2nommu/mmu_context.h b/include/asm-nios2nommu/mmu_context.h new file mode 100644 index 00000000..795cd093 --- /dev/null +++ b/include/asm-nios2nommu/mmu_context.h @@ -0,0 +1,57 @@ +/* + * + * Taken from the m68knommu. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2NOMMU_MMU_CONTEXT_H +#define __NIOS2NOMMU_MMU_CONTEXT_H + +#include +#include +#include + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +extern inline int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + // mm->context = virt_to_phys(mm->pgd); + return(0); +} + +#define destroy_context(mm) do { } while(0) + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) +{ +} + +#define deactivate_mm(tsk,mm) do { } while (0) + +extern inline void activate_mm(struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ +} + +#endif diff --git a/include/asm-nios2nommu/module.h b/include/asm-nios2nommu/module.h new file mode 100644 index 00000000..864f3353 --- /dev/null +++ b/include/asm-nios2nommu/module.h @@ -0,0 +1,36 @@ +#ifndef _NIOS2_MODULE_H +#define _NIOS2_MODULE_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/module.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +struct mod_arch_specific +{ +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#endif /* _NIOS_MODULE_H */ diff --git a/include/asm-nios2nommu/msgbuf.h b/include/asm-nios2nommu/msgbuf.h new file mode 100644 index 00000000..4d090f74 --- /dev/null +++ b/include/asm-nios2nommu/msgbuf.h @@ -0,0 +1,56 @@ +/* + * Taken from the m68k. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2_MSGBUF_H +#define _NIOS2_MSGBUF_H + +/* + * The msqid64_ds structure for nios2 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _NIOS2_MSGBUF_H */ + diff --git a/include/asm-nios2nommu/mutex.h b/include/asm-nios2nommu/mutex.h new file mode 100644 index 00000000..458c1f7f --- /dev/null +++ b/include/asm-nios2nommu/mutex.h @@ -0,0 +1,9 @@ +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + */ + +#include diff --git a/include/asm-nios2nommu/namei.h b/include/asm-nios2nommu/namei.h new file mode 100644 index 00000000..d925c4e4 --- /dev/null +++ b/include/asm-nios2nommu/namei.h @@ -0,0 +1,36 @@ +/* + * linux/include/asm-nios/namei.h + * Moved from m68k version + * Included from linux/fs/namei.c + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __NIOS2_NAMEI_H +#define __NIOS2_NAMEI_H + +/* This dummy routine maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define __emul_prefix() NULL + +#endif diff --git a/include/asm-nios2nommu/ndma.h b/include/asm-nios2nommu/ndma.h new file mode 100644 index 00000000..6b4604df --- /dev/null +++ b/include/asm-nios2nommu/ndma.h @@ -0,0 +1,64 @@ +#ifndef __NDMA_H__ + #define __NDMA_H__ + + #ifndef __ASSEMBLY__ + +// DMA Registers +typedef volatile struct +{ + int np_dmastatus; // status register + int np_dmareadaddress; // read address + int np_dmawriteaddress; // write address + int np_dmalength; // length in bytes + int np_dmareserved1; // reserved + int np_dmareserved2; // reserved + int np_dmacontrol; // control register + int np_dmareserved3; // control register alternate +} np_dma; + +// DMA Register Bits +enum +{ + np_dmacontrol_byte_bit = 0, // Byte transaction + np_dmacontrol_hw_bit = 1, // Half-word transaction + np_dmacontrol_word_bit = 2, // Word transaction + np_dmacontrol_go_bit = 3, // enable execution + np_dmacontrol_i_en_bit = 4, // enable interrupt + np_dmacontrol_reen_bit = 5, // Enable read end-of-packet + np_dmacontrol_ween_bit = 6, // Enable write end-of-packet + np_dmacontrol_leen_bit = 7, // Enable length=0 transaction end + np_dmacontrol_rcon_bit = 8, // Read from a fixed address + np_dmacontrol_wcon_bit = 9, // Write to a fixed address + np_dmacontrol_doubleword_bit = 10, // Double-word transaction + np_dmacontrol_quadword_bit = 11, // Quad-word transaction + + np_dmastatus_done_bit = 0, // 1 when done. Status write clears. + np_dmastatus_busy_bit = 1, // 1 when busy. + np_dmastatus_reop_bit = 2, // read-eop received + np_dmastatus_weop_bit = 3, // write-eop received + np_dmastatus_len_bit = 4, // requested length transacted + + np_dmacontrol_byte_mask = (1 << 0), // Byte transaction + np_dmacontrol_hw_mask = (1 << 1), // Half-word transaction + np_dmacontrol_word_mask = (1 << 2), // Word transaction + np_dmacontrol_go_mask = (1 << 3), // enable execution + np_dmacontrol_i_en_mask = (1 << 4), // enable interrupt + np_dmacontrol_reen_mask = (1 << 5), // Enable read end-of-packet + np_dmacontrol_ween_mask = (1 << 6), // Enable write end-of-packet + np_dmacontrol_leen_mask = (1 << 7), // Enable length=0 transaction end + np_dmacontrol_rcon_mask = (1 << 8), // Read from a fixed address + np_dmacontrol_wcon_mask = (1 << 9), // Write to a fixed address + np_dmacontrol_doubleword_mask = (1 << 10), // Double-word transaction + np_dmacontrol_quadword_mask = (1 << 11), // Quad-word transaction + + np_dmastatus_done_mask = (1 << 0), // 1 when done. Status write clears. + np_dmastatus_busy_mask = (1 << 1), // 1 when busy. + np_dmastatus_reop_mask = (1 << 2), // read-eop received + np_dmastatus_weop_mask = (1 << 3), // write-eop received + np_dmastatus_len_mask = (1 << 4), // requested length transacted +}; + + #endif /* __ASSEMBLY__ */ + +#endif +/* End of File */ diff --git a/include/asm-nios2nommu/nios.h b/include/asm-nios2nommu/nios.h new file mode 100644 index 00000000..df176720 --- /dev/null +++ b/include/asm-nios2nommu/nios.h @@ -0,0 +1,7 @@ +#ifndef __NIOS_H__ +#define __NIOS_H__ + +#include + +#endif + diff --git a/include/asm-nios2nommu/page.h b/include/asm-nios2nommu/page.h new file mode 100644 index 00000000..f784bebf --- /dev/null +++ b/include/asm-nios2nommu/page.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2_PAGE_H +#define _NIOS2_PAGE_H + +/* copied from m68knommu arch */ + +/* PAGE_SHIFT determines the page size */ + +#define PAGE_SHIFT (12) +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifdef __KERNEL__ + +#include + +#if PAGE_SHIFT < 13 +#define THREAD_SIZE (8192) +#else +#define THREAD_SIZE PAGE_SIZE +#endif + +#ifndef __ASSEMBLY__ + +#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) +#define free_user_page(page, addr) free_page(addr) + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd[16]; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((&x)->pmd[0]) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +extern unsigned long memory_start; +extern unsigned long memory_end; + +#endif /* !__ASSEMBLY__ */ +#include +#define PAGE_OFFSET ((int)(nasys_program_mem)) + +#ifndef __ASSEMBLY__ + +#define __pa(vaddr) virt_to_phys((void *)(vaddr)) +#define __va(paddr) phys_to_virt((unsigned long)(paddr)) + +#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) + +#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) +#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) + +#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) +#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) +#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr) + +#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) +#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) +#define pfn_valid(pfn) ((pfn) < max_mapnr) + +#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ + ((void *)(kaddr) < (void *)memory_end)) + +#ifdef CONFIG_NO_KERNEL_MSG +#define BUG_PRINT() +#else +#define BUG_PRINT() printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__) +#endif + +#ifdef na_cpu_oci_core +#define BUG_PANIC() asm volatile ("break") /* drop to debugger */ +#else +// #define BUG_PANIC() while(1) +#define BUG_PANIC() panic("BUG!") +#endif + +#endif /* __ASSEMBLY__ */ + +#include + +#endif /* __KERNEL__ */ + +#endif /* _NIOS2_PAGE_H */ diff --git a/include/asm-nios2nommu/param.h b/include/asm-nios2nommu/param.h new file mode 100644 index 00000000..e75a3551 --- /dev/null +++ b/include/asm-nios2nommu/param.h @@ -0,0 +1,49 @@ +#ifndef _NIOS_PARAM_H +#define _NIOS_PARAM_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/param.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#ifndef HZ +#define HZ 100 +#endif + +#ifdef __KERNEL__ +#define USER_HZ HZ +#define CLOCKS_PER_SEC (USER_HZ) +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif diff --git a/include/asm-nios2nommu/pci.h b/include/asm-nios2nommu/pci.h new file mode 100644 index 00000000..0a523c85 --- /dev/null +++ b/include/asm-nios2nommu/pci.h @@ -0,0 +1,130 @@ +#ifndef __ASM_SH_PCI_H +#define __ASM_SH_PCI_H + +#ifdef __KERNEL__ + +#include + +/* Can be used to override the logic in pci_scan_bus for skipping + already-configured bus numbers - to be used for buggy BIOSes + or architectures with incomplete PCI setup by the loader */ + +#define pcibios_assign_all_busses() 1 +#define pcibios_scan_all_fns(a, b) 0 + +/* + * A board can define one or more PCI channels that represent built-in (or + * external) PCI controllers. + */ +struct pci_channel { + struct pci_ops *pci_ops; + struct resource *io_resource; + struct resource *mem_resource; + int first_devfn; + int last_devfn; +}; + +/* + * Each board initializes this array and terminates it with a NULL entry. + */ +extern struct pci_channel board_pci_channels[]; + +#define PCIBIOS_MIN_IO board_pci_channels->io_resource->start +#define PCIBIOS_MIN_MEM board_pci_channels->mem_resource->start + +struct pci_dev; + +extern void pcibios_set_master(struct pci_dev *dev); + +static inline void pcibios_penalize_isa_irq(int irq, int active) +{ + /* We don't do dynamic PCI IRQ allocation */ +} + +/* Dynamic DMA mapping stuff. + * SuperH has everything mapped statically like x86. + */ + +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (1) + +#include +#include +#include +#include +#include + +/* pci_unmap_{single,page} being a nop depends upon the + * configuration. + */ +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define pci_unmap_addr(PTR, ADDR_NAME) (0) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define pci_unmap_len(PTR, LEN_NAME) (0) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif + +/* Not supporting more than 32-bit PCI bus addresses now, but + * must satisfy references to this function. Change if needed. + */ +#define pci_dac_dma_supported(pci_dev, mask) (0) + +/* These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. + */ +#define sg_dma_address(sg) (virt_to_bus((sg)->dma_address)) +#define sg_dma_len(sg) ((sg)->length) + +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + +/* Board-specific fixup routines. */ +extern void pcibios_fixup(void); +extern void pcibios_fixup_irqs(void); + +#ifdef CONFIG_PCI_AUTO +extern int pciauto_assign_resources(int busno, struct pci_channel *hose); +#endif + +static inline void pcibios_add_platform_entries(struct pci_dev *dev) +{ +} + +#endif /* __KERNEL__ */ + +/* generic pci stuff */ +#include + +/* generic DMA-mapping stuff */ +#include + +#endif /* __ASM_SH_PCI_H */ + diff --git a/include/asm-nios2nommu/percpu.h b/include/asm-nios2nommu/percpu.h new file mode 100644 index 00000000..cd6d4a3a --- /dev/null +++ b/include/asm-nios2nommu/percpu.h @@ -0,0 +1,30 @@ +#ifndef __ARCH_NIOS2NOMMU_PERCPU__ +#define __ARCH_NIOS2NOMMU_PERCPU__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/percpu.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#endif /* __ARCH_NIOS2NOMMU_PERCPU__ */ diff --git a/include/asm-nios2nommu/pgalloc.h b/include/asm-nios2nommu/pgalloc.h new file mode 100644 index 00000000..a997adae --- /dev/null +++ b/include/asm-nios2nommu/pgalloc.h @@ -0,0 +1,32 @@ +#ifndef _NIOS2NOMMU_PGALLOC_H +#define _NIOS2NOMMU_PGALLOC_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/pgalloc.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#define check_pgt_cache() do { } while (0) + +#endif /* _NIOS2NOMMU_PGALLOC_H */ diff --git a/include/asm-nios2nommu/pgtable.h b/include/asm-nios2nommu/pgtable.h new file mode 100644 index 00000000..9c2f0682 --- /dev/null +++ b/include/asm-nios2nommu/pgtable.h @@ -0,0 +1,104 @@ +#ifndef _NIOS_PGTABLE_H +#define _NIOS_PGTABLE_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/pgtable.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#include + +//vic - this bit copied from m68knommu version +#include +#include + +typedef pte_t *pte_addr_t; + +#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) +#define kern_addr_valid(addr) (1) +#define pmd_offset(a, b) ((void *)0) + +#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ +//vic - this bit copied from m68knommu version + +extern void paging_init(void); +#define swapper_pg_dir ((pgd_t *) 0) + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +static inline int pte_file(pte_t pte) { return 0; } + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) (virt_to_page(0)) + +extern unsigned int kobjsize(const void *objp); +extern int is_in_rom(unsigned long); + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + +#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + remap_pfn_range(vma, vaddr, pfn, size, prot) + +extern inline void flush_cache_mm(struct mm_struct *mm) +{ +} + +extern inline void flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ +} + +/* Push the page at kernel virtual address and clear the icache */ +extern inline void flush_page_to_ram (unsigned long address) +{ +} + +/* Push n pages at kernel virtual address and clear the icache */ +extern inline void flush_pages_to_ram (unsigned long address, int n) +{ +} + +/* + * All 32bit addresses are effectively valid for vmalloc... + * Sort of meaningless for non-VM targets. + */ +#define VMALLOC_START 0 +#define VMALLOC_END 0xffffffff + +#endif /* _NIOS_PGTABLE_H */ diff --git a/include/asm-nios2nommu/pio_struct.h b/include/asm-nios2nommu/pio_struct.h new file mode 100644 index 00000000..8ce51762 --- /dev/null +++ b/include/asm-nios2nommu/pio_struct.h @@ -0,0 +1,14 @@ +// PIO Peripheral + +// PIO Registers +typedef volatile struct + { + int np_piodata; // read/write, up to 32 bits + int np_piodirection; // write/readable, up to 32 bits, 1->output bit + int np_piointerruptmask; // write/readable, up to 32 bits, 1->enable interrupt + int np_pioedgecapture; // read, up to 32 bits, cleared by any write + } np_pio; + +// PIO Routines +void nr_pio_showhex(int value); // shows low byte on pio named na_seven_seg_pio + diff --git a/include/asm-nios2nommu/poll.h b/include/asm-nios2nommu/poll.h new file mode 100644 index 00000000..f6b9ab8a --- /dev/null +++ b/include/asm-nios2nommu/poll.h @@ -0,0 +1,48 @@ +#ifndef __NIOS2_POLL_H +#define __NIOS2_POLL_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/poll.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#define POLLIN 1 +#define POLLPRI 2 +#define POLLOUT 4 +#define POLLERR 8 +#define POLLHUP 16 +#define POLLNVAL 32 +#define POLLRDNORM 64 +#define POLLWRNORM POLLOUT +#define POLLRDBAND 128 +#define POLLWRBAND 256 +#define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 +#define POLLRDHUP 0x2000 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif diff --git a/include/asm-nios2nommu/posix_types.h b/include/asm-nios2nommu/posix_types.h new file mode 100644 index 00000000..0b019b50 --- /dev/null +++ b/include/asm-nios2nommu/posix_types.h @@ -0,0 +1,89 @@ +#ifndef __ARCH_NIOS2_POSIX_TYPES_H +#define __ARCH_NIOS2_POSIX_TYPES_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/posix_types.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) + +#undef __FD_CLR +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) + +#undef __FD_ISSET +#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif diff --git a/include/asm-nios2nommu/preem_latency.h b/include/asm-nios2nommu/preem_latency.h new file mode 100644 index 00000000..6defb5c2 --- /dev/null +++ b/include/asm-nios2nommu/preem_latency.h @@ -0,0 +1,39 @@ +#ifndef _ASM_PREEM_LATENCY_H +#define _ASM_PREEM_LATENCY_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/preem_latency.h + * + * timing support for preempt-stats patch + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#define readclock(low) \ +do {\ + *(volatile unsigned long *)na_Counter_64_bit=1; \ + low=*(volatile unsigned long *)na_Counter_64_bit; \ +} while (0) +#define readclock_init() + +#endif /* _ASM_PREEM_LATENCY_H */ diff --git a/include/asm-nios2nommu/processor.h b/include/asm-nios2nommu/processor.h new file mode 100644 index 00000000..5332f940 --- /dev/null +++ b/include/asm-nios2nommu/processor.h @@ -0,0 +1,148 @@ +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/processor.h + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2001 Ken Hill (khill@microtronix.com) + * Vic Phillips (vic@microtronix.com) + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * hacked from: + * include/asm-sparc/processor.h + * + * 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. + * + * + * Jan/20/2004 dgt NiosII + * Nov/02/2003 dgt Fix task_size + * + ---------------------------------------------------------------------*/ + +#ifndef __ASM_NIOS_PROCESSOR_H +#define __ASM_NIOS_PROCESSOR_H + +#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ +#define NIOS2_FLAG_COPROC 0x00000002 /* Thread used coprocess */ +#define NIOS2_FLAG_DEBUG 0x00000004 /* task is being debugged */ + +#define NIOS2_OP_NOP 0x1883a +#define NIOS2_OP_BREAK 0x3da03a + +#ifndef __ASSEMBLY__ + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#include +#include + +#include +#include +#include +#include +#include /* for get_hi_limit */ + +/* + * Bus types + */ +#define EISA_bus 0 +#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +/* + * The nios has no problems with write protection + */ +#define wp_works_ok 1 +#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ + +/* Whee, this is STACK_TOP and the lowest kernel address too... */ +#if 0 +#define KERNBASE 0x00000000 /* First address the kernel will eventually be */ +#define TASK_SIZE (KERNBASE) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) +#endif + +#define TASK_SIZE ((unsigned int) nasys_program_mem_end) //...this is better... + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. We won't be using it + */ +#define TASK_UNMAPPED_BASE 0 + +/* The Nios processor specific thread struct. */ +struct thread_struct { + struct pt_regs *kregs; + + /* For signal handling */ + unsigned long sig_address; + unsigned long sig_desc; + + /* Context switch saved kernel state. */ + unsigned long ksp; + unsigned long kpsr; + unsigned long kesr; + + /* Flags are defined below */ + + unsigned long flags; + int current_ds; + struct exec core_exec; /* just what it says. */ +}; + +#define INIT_MMAP { &init_mm, (0), (0), \ + __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC } + +#define INIT_THREAD { \ + .kregs = 0, \ + .sig_address = 0, \ + .sig_desc = 0, \ + .ksp = 0, \ + .kpsr = 0, \ + .kesr = PS_S, \ + .flags = NIOS2_FLAG_KTHREAD, \ + .current_ds = __KERNEL_DS, \ + .core_exec = INIT_EXEC \ +} + +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + +extern unsigned long thread_saved_pc(struct task_struct *t); + +extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) +#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) + +#ifdef __KERNEL__ +/* Allocation and freeing of basic task resources. */ + +//;dgt2;#define alloc_task_struct() ((struct task_struct *) xx..see..linux..fork..xx __get_free_pages(GFP_KERNEL,1)) +//;dgt2;#define get_task_struct(tsk) xx..see..linux..sched.h...atomic_inc(&mem_map[MAP_NR(tsk)].count) + +#endif + +#define cpu_relax() do { } while (0) +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_NIOS_PROCESSOR_H */ diff --git a/include/asm-nios2nommu/ptrace.h b/include/asm-nios2nommu/ptrace.h new file mode 100644 index 00000000..c4e20c3e --- /dev/null +++ b/include/asm-nios2nommu/ptrace.h @@ -0,0 +1,141 @@ +/* + * Taken from the m68k port. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _NIOS2NOMMU_PTRACE_H +#define _NIOS2NOMMU_PTRACE_H + +#ifndef __ASSEMBLY__ + +#define PTR_R0 0 +#define PTR_R1 1 +#define PTR_R2 2 +#define PTR_R3 3 +#define PTR_R4 4 +#define PTR_R5 5 +#define PTR_R6 6 +#define PTR_R7 7 +#define PTR_R8 8 +#define PTR_R9 9 +#define PTR_R10 10 +#define PTR_R11 11 +#define PTR_R12 12 +#define PTR_R13 13 +#define PTR_R14 14 +#define PTR_R15 15 +#define PTR_R16 16 +#define PTR_R17 17 +#define PTR_R18 18 +#define PTR_R19 19 +#define PTR_R20 20 +#define PTR_R21 21 +#define PTR_R22 22 +#define PTR_R23 23 +#define PTR_R24 24 +#define PTR_R25 25 +#define PTR_GP 26 +#define PTR_SP 27 +#define PTR_FP 28 +#define PTR_EA 29 +#define PTR_BA 30 +#define PTR_RA 31 +#define PTR_STATUS 32 +#define PTR_ESTATUS 33 +#define PTR_BSTATUS 34 +#define PTR_IENABLE 35 +#define PTR_IPENDING 36 + +/* this struct defines the way the registers are stored on the + stack during a system call. + + There is a fake_regs in setup.c that has to match pt_regs.*/ + +struct pt_regs { + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long r14; + unsigned long r15; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long orig_r2; + unsigned long ra; + unsigned long fp; + unsigned long sp; + unsigned long gp; + unsigned long estatus; + unsigned long status_extension; + unsigned long ea; +}; + + +/* + * This is the extended stack used by signal handlers and the context + * switcher: it's pushed after the normal "struct pt_regs". + */ +struct switch_stack { + unsigned long r16; + unsigned long r17; + unsigned long r18; + unsigned long r19; + unsigned long r20; + unsigned long r21; + unsigned long r22; + unsigned long r23; + unsigned long fp; + unsigned long gp; + unsigned long ra; +}; + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#ifdef CONFIG_FPU +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#endif + +#ifdef __KERNEL__ + +#ifndef PS_S +#define PS_S (0x00000001) +#endif +#ifndef PS_T +#define PS_T (0x00000002) +#endif + +#define user_mode(regs) (!((regs)->status_extension & PS_S)) +#define instruction_pointer(regs) ((regs)->ra) +#define profile_pc(regs) instruction_pointer(regs) +extern void show_regs(struct pt_regs *); + +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _NIOS2NOMMU_PTRACE_H */ diff --git a/include/asm-nios2nommu/resource.h b/include/asm-nios2nommu/resource.h new file mode 100644 index 00000000..9c2499a8 --- /dev/null +++ b/include/asm-nios2nommu/resource.h @@ -0,0 +1,6 @@ +#ifndef __ASM_SH_RESOURCE_H +#define __ASM_SH_RESOURCE_H + +#include + +#endif /* __ASM_SH_RESOURCE_H */ diff --git a/include/asm-nios2nommu/rmap.h b/include/asm-nios2nommu/rmap.h new file mode 100644 index 00000000..b3664ccd --- /dev/null +++ b/include/asm-nios2nommu/rmap.h @@ -0,0 +1,2 @@ +/* Do not need anything here */ + diff --git a/include/asm-nios2nommu/scatterlist.h b/include/asm-nios2nommu/scatterlist.h new file mode 100644 index 00000000..20898e27 --- /dev/null +++ b/include/asm-nios2nommu/scatterlist.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SH_SCATTERLIST_H +#define __ASM_SH_SCATTERLIST_H + +struct scatterlist { + struct page * page; /* Location for highmem page, if any */ + unsigned int offset;/* for highmem, page offset */ + dma_addr_t dma_address; + unsigned int length; +}; + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* !(__ASM_SH_SCATTERLIST_H) */ diff --git a/include/asm-nios2nommu/sections.h b/include/asm-nios2nommu/sections.h new file mode 100644 index 00000000..61b3f711 --- /dev/null +++ b/include/asm-nios2nommu/sections.h @@ -0,0 +1,30 @@ +#ifndef _NIOS2NOMMU_SECTIONS_H +#define _NIOS2NOMMU_SECTIONS_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/sections.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#endif /* _NIOS2NOMMU_SECTIONS_H */ diff --git a/include/asm-nios2nommu/segment.h b/include/asm-nios2nommu/segment.h new file mode 100644 index 00000000..25871b3c --- /dev/null +++ b/include/asm-nios2nommu/segment.h @@ -0,0 +1,75 @@ +#ifndef _NIOS2NOMMU_SEGMENT_H +#define _NIOS2NOMMU_SEGMENT_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/segment.h + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* define constants */ +/* Address spaces (FC0-FC2) */ +#define USER_DATA (1) +#ifndef __USER_DS +#define __USER_DS (USER_DATA) +#endif +#define USER_PROGRAM (2) +#define SUPER_DATA (5) +#ifndef __KERNEL_DS +#define __KERNEL_DS (SUPER_DATA) +#endif +#define SUPER_PROGRAM (6) +#define CPU_SPACE (7) + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define USER_DS MAKE_MM_SEG(__USER_DS) +#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) + +/* + * Get/set the SFC/DFC registers for MOVES instructions + */ + +static inline mm_segment_t get_fs(void) +{ + return USER_DS; +} + +static inline mm_segment_t get_ds(void) +{ + /* return the supervisor data space code */ + return KERNEL_DS; +} + +static inline void set_fs(mm_segment_t val) +{ +} + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#endif /* __ASSEMBLY__ */ + +#endif /* _NIOS2NOMMU_SEGMENT_H */ diff --git a/include/asm-nios2nommu/semaphore-helper.h b/include/asm-nios2nommu/semaphore-helper.h new file mode 100644 index 00000000..a8905d13 --- /dev/null +++ b/include/asm-nios2nommu/semaphore-helper.h @@ -0,0 +1,99 @@ +#ifndef _NIOS2NOMMU_SEMAPHORE_HELPER_H +#define _NIOS2NOMMU_SEMAPHORE_HELPER_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/semaphore.h + * + * SMP- and interrupt-safe semaphores helper functions. + * + * Derived from M68knommu + * + * (C) Copyright 1996 Linus Torvalds + * m68k version by Andreas Schwab + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +/* + * These two _must_ execute atomically wrt each other. + */ +static inline void wake_one_more(struct semaphore * sem) +{ + atomic_inc(&sem->waking); +} + +static inline int waking_non_zero(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_interruptible: + * 1 got the lock + * 0 go to sleep + * -EINTR interrupted + */ +static inline int waking_non_zero_interruptible(struct semaphore *sem, + struct task_struct *tsk) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } else if (signal_pending(tsk)) { + atomic_inc(&sem->count); + ret = -EINTR; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_trylock: + * 1 failed to lock + * 0 got the lock + */ +static inline int waking_non_zero_trylock(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 1; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 0; + } else + atomic_inc(&sem->count); + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +#endif diff --git a/include/asm-nios2nommu/semaphore.h b/include/asm-nios2nommu/semaphore.h new file mode 100644 index 00000000..8d66c77e --- /dev/null +++ b/include/asm-nios2nommu/semaphore.h @@ -0,0 +1,152 @@ +#ifndef _NIOS2NOMMU_SEMAPHORE_H +#define _NIOS2NOMMU_SEMAPHORE_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/semaphore.h + * + * Interrupt-safe semaphores.. + * + * Derived from M68knommu + * + * (C) Copyright 1996 Linus Torvalds + * m68k version by Andreas Schwab + * Copyright (C) 2004 Microtronix Datacom 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. + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#define RW_LOCK_BIAS 0x01000000 + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +#include +#include + +struct semaphore { + atomic_t count; + atomic_t waking; + wait_queue_head_t wait; +}; + +#define __SEMAPHORE_INITIALIZER(name, n) \ +{ \ + .count = ATOMIC_INIT(n), \ + .waking = ATOMIC_INIT(0), \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ +} + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +static inline void sema_init (struct semaphore *sem, int val) +{ + *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init(sem, 0); +} + +asmlinkage void __down_failed(void /* special register calling convention */); +asmlinkage int __down_failed_interruptible(void /* params in registers */); +asmlinkage int __down_failed_trylock(void /* params in registers */); +asmlinkage void __up_wakeup(void /* special register calling convention */); + +asmlinkage void __down(struct semaphore * sem); +asmlinkage int __down_interruptible(struct semaphore * sem); +asmlinkage int __down_trylock(struct semaphore * sem); +asmlinkage void __up(struct semaphore * sem); + +extern spinlock_t semaphore_wake_lock; + +/* + * This is ugly, but we want the default case to fall through. + * "down_failed" is a special asm handler that calls the C + * routine that actually waits. + */ +static inline void down(struct semaphore * sem) +{ + might_sleep(); + + #if 0 + ...Nios2 has no atomic "decrement memory".... + #else + if (atomic_dec_return(&sem->count) < 0) + __down(sem); + #endif +} + +static inline int down_interruptible(struct semaphore * sem) +{ + int ret = 0; + + + might_sleep(); + + #if 0 + ...Nios2 has no atomic "decrement memory".... + #else + if(atomic_dec_return(&sem->count) < 0) + ret = __down_interruptible(sem); + return ret; + #endif +} + +static inline int down_trylock(struct semaphore * sem) +{ + #if 0 + ...Nios2 has no atomic "decrement memory".... + #else + int ret = 0; + + if (atomic_dec_return (&sem->count) < 0) + ret = __down_trylock(sem); + return ret; + #endif +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +static inline void up(struct semaphore * sem) +{ + #if 0 + ...Nios2 has no atomic "increment memory".... + #else + if (atomic_inc_return(&sem->count) <= 0) + __up(sem); + #endif +} + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/include/asm-nios2nommu/sembuf.h b/include/asm-nios2nommu/sembuf.h new file mode 100644 index 00000000..e530cab2 --- /dev/null +++ b/include/asm-nios2nommu/sembuf.h @@ -0,0 +1,48 @@ +#ifndef _NIOS_SEMBUF_H +#define _NIOS_SEMBUF_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/sembuf.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _NIOS_SEMBUF_H */ diff --git a/include/asm-nios2nommu/setup.h b/include/asm-nios2nommu/setup.h new file mode 100644 index 00000000..c5a655af --- /dev/null +++ b/include/asm-nios2nommu/setup.h @@ -0,0 +1,31 @@ +/* Copied from i386 port. + * Just a place holder. We don't want to have to test x86 before + * we include stuff + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2_SETUP_H +#define _NIOS2_SETUP_H + +#define COMMAND_LINE_SIZE 512 + +#endif /* _NIOS2_SETUP_H */ diff --git a/include/asm-nios2nommu/shmbuf.h b/include/asm-nios2nommu/shmbuf.h new file mode 100644 index 00000000..f6e6e7dd --- /dev/null +++ b/include/asm-nios2nommu/shmbuf.h @@ -0,0 +1,64 @@ +#ifndef _NIOS_SHMBUF_H +#define _NIOS_SHMBUF_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/shmbuf.h + * + * Derived from m68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _NIOS_SHMBUF_H */ diff --git a/include/asm-nios2nommu/shmparam.h b/include/asm-nios2nommu/shmparam.h new file mode 100644 index 00000000..94efe2db --- /dev/null +++ b/include/asm-nios2nommu/shmparam.h @@ -0,0 +1,30 @@ +#ifndef __NIOS2NOMMU_SHMPARAM_H__ +#define __NIOS2NOMMU_SHMPARAM_H__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/shmparam.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ + +#endif /* __NIOS2NOMMU_SHMPARAM_H__ */ diff --git a/include/asm-nios2nommu/sigcontext.h b/include/asm-nios2nommu/sigcontext.h new file mode 100644 index 00000000..7321e7d0 --- /dev/null +++ b/include/asm-nios2nommu/sigcontext.h @@ -0,0 +1,35 @@ +/* + * Taken from the m68knommu. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ASM_NIOS2NOMMU_SIGCONTEXT_H +#define _ASM_NIOS2NOMMU_SIGCONTEXT_H + +#include + +struct sigcontext { + struct pt_regs regs; + unsigned long sc_mask; /* old sigmask */ +}; + +#endif diff --git a/include/asm-nios2nommu/siginfo.h b/include/asm-nios2nommu/siginfo.h new file mode 100644 index 00000000..c047c0b2 --- /dev/null +++ b/include/asm-nios2nommu/siginfo.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2NOMMU_SIGINFO_H +#define _NIOS2NOMMU_SIGINFO_H + +#include + +#endif diff --git a/include/asm-nios2nommu/signal.h b/include/asm-nios2nommu/signal.h new file mode 100644 index 00000000..c86a20c1 --- /dev/null +++ b/include/asm-nios2nommu/signal.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2_SIGNAL_H +#define _NIOS2_SIGNAL_H + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX _NSIG + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#include + +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ + +#include +#undef __HAVE_ARCH_SIG_BITOPS + +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + +#endif /* __KERNEL__ */ + +#endif /* _NIOS2_SIGNAL_H */ diff --git a/include/asm-nios2nommu/smp.h b/include/asm-nios2nommu/smp.h new file mode 100644 index 00000000..fb233075 --- /dev/null +++ b/include/asm-nios2nommu/smp.h @@ -0,0 +1,32 @@ +#ifndef __ASM_SMP_H +#define __ASM_SMP_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/smp.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#ifdef CONFIG_SMP +#error SMP not supported +#endif + +#endif diff --git a/include/asm-nios2nommu/socket.h b/include/asm-nios2nommu/socket.h new file mode 100644 index 00000000..ca77fbe5 --- /dev/null +++ b/include/asm-nios2nommu/socket.h @@ -0,0 +1,77 @@ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/socket.h + * + * Derived from m68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +/* For setsockopt(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +#define SO_PEERSEC 31 /* ;dgt2;tmp; */ +#define SO_PASSSEC 34 + +#endif /* _ASM_SOCKET_H */ diff --git a/include/asm-nios2nommu/sockios.h b/include/asm-nios2nommu/sockios.h new file mode 100644 index 00000000..d9c181b3 --- /dev/null +++ b/include/asm-nios2nommu/sockios.h @@ -0,0 +1,38 @@ +#ifndef _ASM_NIOS_SOCKIOS_H +#define _ASM_NIOS_SOCKIOS_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/sockios.h + * + * Socket-level I/O control calls. + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif /* !(_ASM_NIOS_SOCKIOS_H) */ + diff --git a/include/asm-nios2nommu/spi.h b/include/asm-nios2nommu/spi.h new file mode 100644 index 00000000..6efb82ce --- /dev/null +++ b/include/asm-nios2nommu/spi.h @@ -0,0 +1,92 @@ +#ifndef _ASM_SPI_H_ +#define _ASM_SPI_H_ 1 + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/spi.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +int register_NIOS_SPI( void ); +void unregister_NIOS_SPI( void ); + +#if defined(MODULE) +void cleanup_module( void ); +int init_module( void ); +#endif + +#if defined(__KERNEL__) +int spi_reset ( void ); +#endif + + +#define clockCS 0x01 +#define temperatureCS 0x02 + +#define clock_read_base 0x00 +#define clock_write_base 0x80 +#define clock_read_control 0x0F +#define clock_read_trickle 0x11 + +#define clock_read_sec 0x00 +#define clock_read_min 0x01 +#define clock_read_hour 0x02 +#define clock_read_day 0x03 +#define clock_read_date 0x04 +#define clock_read_month 0x05 +#define clock_read_year 0x06 + +#define clock_write_control 0x8F +#define clock_write_trickle 0x91 +#define clock_write_sec 0x80 +#define clock_write_min 0x81 +#define clock_write_hour 0x82 +#define clock_write_day 0x83 +#define clock_write_date 0x84 +#define clock_write_month 0x85 +#define clock_write_year 0x86 + +#define clock_write_ram_start 0xA0 +#define clock_write_ram_end 0x100 +#define clock_read_ram_start 0x20 +#define clock_read_ram_end 0x80 + + +#define clock_sec_def 0x11 +#define clock_min_def 0x59 +#define clock_hour_def 0x71 +#define clock_day_def 0x00 +#define clock_date_def 0x20 +#define clock_month_def 0x12 +#define clock_year_def 0x34 + +#define temp_read_base 0x00 +#define temp_write_base 0x80 +#define temp_read_control 0x00 +#define temp_write_control 0x80 +#define temp_read_msb 0x02 +#define temp_read_lsb 0x01 + +#define MAX_TEMP_VAR 10 + +#endif /*_ASM_SPI_H_*/ diff --git a/include/asm-nios2nommu/spi_struct.h b/include/asm-nios2nommu/spi_struct.h new file mode 100644 index 00000000..c7b2faf3 --- /dev/null +++ b/include/asm-nios2nommu/spi_struct.h @@ -0,0 +1,57 @@ +// SPI Registers +typedef volatile struct + { + int np_spirxdata; // Read-only, 1-16 bit + int np_spitxdata; // Write-only, same width as rxdata + int np_spistatus; // Read-only, 9-bit + int np_spicontrol; // Read/Write, 9-bit + int np_spireserved; // reserved + int np_spislaveselect; // Read/Write, 1-16 bit, master only + int np_spiendofpacket; // Read/write, same width as txdata, rxdata. + } np_spi; + +// SPI Status Register Bits +enum + { + np_spistatus_eop_bit = 9, + np_spistatus_e_bit = 8, + np_spistatus_rrdy_bit = 7, + np_spistatus_trdy_bit = 6, + np_spistatus_tmt_bit = 5, + np_spistatus_toe_bit = 4, + np_spistatus_roe_bit = 3, + + np_spistatus_eop_mask = (1 << 9), + np_spistatus_e_mask = (1 << 8), + np_spistatus_rrdy_mask = (1 << 7), + np_spistatus_trdy_mask = (1 << 6), + np_spistatus_tmt_mask = (1 << 5), + np_spistatus_toe_mask = (1 << 4), + np_spistatus_roe_mask = (1 << 3), + }; + +// SPI Control Register Bits +enum + { + np_spicontrol_sso_bit = 10, + np_spicontrol_ieop_bit = 9, + np_spicontrol_ie_bit = 8, + np_spicontrol_irrdy_bit = 7, + np_spicontrol_itrdy_bit = 6, + np_spicontrol_itoe_bit = 4, + np_spicontrol_iroe_bit = 3, + + np_spicontrol_sso_mask = (1 << 10), + np_spicontrol_ieop_mask = (1 << 9), + np_spicontrol_ie_mask = (1 << 8), + np_spicontrol_irrdy_mask = (1 << 7), + np_spicontrol_itrdy_mask = (1 << 6), + np_spicontrol_itoe_mask = (1 << 4), + np_spicontrol_iroe_mask = (1 << 3), + }; + +// SPI Routines. +int nr_spi_rxchar(np_spi *spiBase); +int nr_spi_txchar(int i, np_spi *spiBase); + + diff --git a/include/asm-nios2nommu/spinlock.h b/include/asm-nios2nommu/spinlock.h new file mode 100644 index 00000000..f5187556 --- /dev/null +++ b/include/asm-nios2nommu/spinlock.h @@ -0,0 +1,30 @@ +#ifndef __NIOS_SPINLOCK_H +#define __NIOS_SPINLOCK_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/spinlock.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#error "Nios doesn't do SMP yet" + +#endif diff --git a/include/asm-nios2nommu/stat.h b/include/asm-nios2nommu/stat.h new file mode 100644 index 00000000..bd27a97a --- /dev/null +++ b/include/asm-nios2nommu/stat.h @@ -0,0 +1,102 @@ +#ifndef _ASMNIOS2NOMMU_STAT_H +#define _ASMNIOS2NOMMU_STAT_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/stat.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned long long st_dev; + unsigned char __pad1[4]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned char __pad3[4]; + + long long st_size; + unsigned long st_blksize; + + unsigned long __pad4; /* future possible st_blocks high bits */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; + + unsigned long long st_ino; +}; + +#endif diff --git a/include/asm-nios2nommu/statfs.h b/include/asm-nios2nommu/statfs.h new file mode 100644 index 00000000..c4637f66 --- /dev/null +++ b/include/asm-nios2nommu/statfs.h @@ -0,0 +1,30 @@ +#ifndef _NIOS2NOMMU_STATFS_H +#define _NIOS2NOMMU_STATFS_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/statfs.h + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#endif /* _NIOS2NOMMU_STATFS_H */ diff --git a/include/asm-nios2nommu/string.h b/include/asm-nios2nommu/string.h new file mode 100644 index 00000000..7e394790 --- /dev/null +++ b/include/asm-nios2nommu/string.h @@ -0,0 +1,45 @@ +#ifndef __NIOS_STRING_H__ +#define __NIOS_STRING_H__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/string.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#ifdef __KERNEL__ /* only set these up for kernel code */ + +#define __HAVE_ARCH_MEMMOVE +void * memmove(void * d, const void * s, size_t count); +#define __HAVE_ARCH_MEMCPY +extern void * memcpy(void *d, const void *s, size_t count); +#define __HAVE_ARCH_MEMSET +extern void * memset(void * s,int c,size_t count); + +#if 0 +#define __HAVE_ARCH_BCOPY +#define __HAVE_ARCH_STRLEN +#endif + +#endif /* KERNEL */ + +#endif /* !(__NIOS_STRING_H__) */ diff --git a/include/asm-nios2nommu/system.h b/include/asm-nios2nommu/system.h new file mode 100644 index 00000000..a6ea4c87 --- /dev/null +++ b/include/asm-nios2nommu/system.h @@ -0,0 +1,171 @@ +/* + * Taken from the m68k. + * + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _NIOS2NOMMU_SYSTEM_H +#define _NIOS2NOMMU_SYSTEM_H + +#include +#include +#include +#include + +/* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. This + * also clears the TS-flag if the task we switched to has used the + * math co-processor latest. + */ + +/* + */ +asmlinkage void resume(void); +#define switch_to(prev,next,last) \ +{ \ + void *_last; \ + __asm__ __volatile__( \ + "mov r4, %1\n" \ + "mov r5, %2\n" \ + "call resume\n" \ + "mov %0,r4\n" \ + : "=r" (_last) \ + : "r" (prev), "r" (next) \ + : "r4","r5","r7","r8","ra"); \ + (last) = _last; \ +} + +#define local_irq_enable() __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "ori r8, r8, 1\n" \ + "wrctl status, r8\n" \ + : : : "r8") + +#define local_irq_disable() __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "andi r8, r8, 0xfffe\n" \ + "wrctl status, r8\n" \ + : : : "r8") + +#define local_save_flags(x) __asm__ __volatile__ ( \ + "rdctl r8, status\n" \ + "mov %0, r8\n" \ + :"=r" (x) : : "r8", "memory") + +#define local_irq_restore(x) __asm__ __volatile__ ( \ + "mov r8, %0\n" \ + "wrctl status, r8\n" \ + : :"r" (x) : "memory") + +/* For spinlocks etc */ +#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0) + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + ((flags & NIOS2_STATUS_PIE_MSK) == 0x0); \ +}) + +#define iret() __asm__ __volatile__ ("eret": : :"memory", "ea") + +/* + * Force strict CPU ordering. + * Not really required on m68k... + */ +#define nop() asm volatile ("nop"::) +#define mb() asm volatile ("" : : :"memory") +#define rmb() asm volatile ("" : : :"memory") +#define wmb() asm volatile ("" : : :"memory") +#define set_rmb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) set_rmb(var, value) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) +#endif + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((volatile struct __xchg_dummy *)(x)) + +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + unsigned long tmp, flags; + + local_irq_save(flags); + + switch (size) { + case 1: + __asm__ __volatile__( \ + "ldb %0, %2\n" \ + "stb %1, %2\n" \ + : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 2: + __asm__ __volatile__( \ + "ldh %0, %2\n" \ + "sth %1, %2\n" \ + : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 4: + __asm__ __volatile__( \ + "ldw %0, %2\n" \ + "stw %1, %2\n" \ + : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory"); + break; + } + local_irq_restore(flags); + return tmp; +} + +/* + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + */ +#define __HAVE_ARCH_CMPXCHG 1 + +static __inline__ unsigned long +cmpxchg(volatile int *p, int old, int new) +{ + unsigned long flags; + int prev; + + local_irq_save(flags); + if ((prev = *p) == old) + *p = new; + local_irq_restore(flags); + return(prev); +} + +#endif /* _NIOS2NOMMU_SYSTEM_H */ diff --git a/include/asm-nios2nommu/termbits.h b/include/asm-nios2nommu/termbits.h new file mode 100644 index 00000000..2e89e5b7 --- /dev/null +++ b/include/asm-nios2nommu/termbits.h @@ -0,0 +1,199 @@ +#ifndef __ARCH_NIOS_TERMBITS_H__ +#define __ARCH_NIOS_TERMBITS_H__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/termbits.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* __ARCH_NIOS_TERMBITS_H__ */ diff --git a/include/asm-nios2nommu/termios.h b/include/asm-nios2nommu/termios.h new file mode 100644 index 00000000..db0dddfb --- /dev/null +++ b/include/asm-nios2nommu/termios.h @@ -0,0 +1,132 @@ +#ifndef _NIOS_TERMIOS_H +#define _NIOS_TERMIOS_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/termios.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#ifdef __KERNEL__ +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" +#endif + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 /* X.25 async */ +#define N_6PACK 7 +#define N_MASC 8 /* Reserved for Mobitex module */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ +#define N_HDLC 13 /* synchronous HDLC */ +#define N_SYNC_PPP 14 +#define N_HCI 15 /* Bluetooth HCI UART */ + +#ifdef __KERNEL__ + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +#define user_termio_to_kernel_termios(termios, termio) \ +({ \ + unsigned short tmp; \ + get_user(tmp, &(termio)->c_iflag); \ + (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ + get_user(tmp, &(termio)->c_oflag); \ + (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ + get_user(tmp, &(termio)->c_cflag); \ + (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ + get_user(tmp, &(termio)->c_lflag); \ + (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ + get_user((termios)->c_line, &(termio)->c_line); \ + copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ +}) + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +#define kernel_termios_to_user_termio(termio, termios) \ +({ \ + put_user((termios)->c_iflag, &(termio)->c_iflag); \ + put_user((termios)->c_oflag, &(termio)->c_oflag); \ + put_user((termios)->c_cflag, &(termio)->c_cflag); \ + put_user((termios)->c_lflag, &(termio)->c_lflag); \ + put_user((termios)->c_line, &(termio)->c_line); \ + copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ +}) + +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* _NIOS_TERMIOS_H */ diff --git a/include/asm-nios2nommu/thread_info.h b/include/asm-nios2nommu/thread_info.h new file mode 100644 index 00000000..6d51e0cb --- /dev/null +++ b/include/asm-nios2nommu/thread_info.h @@ -0,0 +1,127 @@ +/* thread_info.h: niosnommu low-level thread information + * adapted from the m68knommu + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 2002 Microtronix Datacom + * + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#include + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +/* + * low level task data. + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + int cpu; /* cpu we're on */ + int preempt_count; /* 0 => preemptable, <0 => BUG*/ + struct restart_block restart_block; +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + + +/* how to get the thread information struct from C + usable only in supervisor mode */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + __asm__ __volatile__( + "mov %0, sp\n" + "and %0, %0, %1\n" + : "=&r"(ti) + : "r" (~(THREAD_SIZE-1)) + ); + return ti; +} + +/* thread information allocation */ +#define alloc_thread_info(tsk) ((struct thread_info *) \ + __get_free_pages(GFP_KERNEL, 1)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * thread information flag bit numbers + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ +#define TIF_MEMDIE 5 + +/* as above, but as bit values */ +#define _TIF_SYSCALL_TRACE (1< + + +#define CLOCK_TICK_RATE nasys_clock_freq /* Underlying HZ */ + +#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ + +#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ + (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ + << (SHIFT_SCALE-SHIFT_HZ)) / HZ) + +typedef unsigned long cycles_t; + +static inline cycles_t get_cycles(void) +{ + return 0; +} + +#endif diff --git a/include/asm-nios2nommu/tlb.h b/include/asm-nios2nommu/tlb.h new file mode 100644 index 00000000..c597b257 --- /dev/null +++ b/include/asm-nios2nommu/tlb.h @@ -0,0 +1,35 @@ +#ifndef __NIOS_TLB_H__ +#define __NIOS_TLB_H__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/tlb.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2003 Microtronix Datacom Ltd + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * 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. + * + * + * Written by Miles Bader + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#define tlb_flush(tlb) ((void)0) + +#include + +#endif /* __NIOS_TLB_H__ */ + diff --git a/include/asm-nios2nommu/tlbflush.h b/include/asm-nios2nommu/tlbflush.h new file mode 100644 index 00000000..63cbe525 --- /dev/null +++ b/include/asm-nios2nommu/tlbflush.h @@ -0,0 +1,86 @@ +#ifndef _NIOS2NOMMU_TLBFLUSH_H +#define _NIOS2NOMMU_TLBFLUSH_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/tlbflush.h + * + * Ported from m68knommu. + * + * Copyright (C) 2003 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + +#include + +/* + * flush all user-space atc entries. + */ +static inline void __flush_tlb(void) +{ + BUG(); +} + +static inline void __flush_tlb_one(unsigned long addr) +{ + BUG(); +} + +#define flush_tlb() __flush_tlb() + +/* + * flush all atc entries (both kernel and user-space entries). + */ +static inline void flush_tlb_all(void) +{ + BUG(); +} + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +{ + BUG(); +} + +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG(); +} + +extern inline void flush_tlb_kernel_page(unsigned long addr) +{ + BUG(); +} + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG(); +} + +#endif /* _NIOS2NOMMU_TLBFLUSH_H */ diff --git a/include/asm-nios2nommu/topology.h b/include/asm-nios2nommu/topology.h new file mode 100644 index 00000000..cfe1054f --- /dev/null +++ b/include/asm-nios2nommu/topology.h @@ -0,0 +1,30 @@ +#ifndef _ASM_NIOS2NOMMU_TOPOLOGY_H +#define _ASM_NIOS2NOMMU_TOPOLOGY_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/topology.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +#endif /* _ASM_NIOS2NOMMU_TOPOLOGY_H */ diff --git a/include/asm-nios2nommu/traps.h b/include/asm-nios2nommu/traps.h new file mode 100644 index 00000000..e03ef7f7 --- /dev/null +++ b/include/asm-nios2nommu/traps.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _NIOS2_TRAPS_H +#define _NIOS2_TRAPS_H + +#define TRAP_ID_SYSCALL 0 +#define TRAP_ID_APPDEBUG 1 +#endif /* !(_NIOS2_TRAPS_H) */ diff --git a/include/asm-nios2nommu/types.h b/include/asm-nios2nommu/types.h new file mode 100644 index 00000000..dd7a48e2 --- /dev/null +++ b/include/asm-nios2nommu/types.h @@ -0,0 +1,91 @@ +#ifndef _NIOS_TYPES_H +#define _NIOS_TYPES_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/types.h + * + * Derived from m68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#ifndef __ASSEMBLY__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +/* DMA addresses are always 32-bits wide */ + +typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _NIOS_TYPES_H */ diff --git a/include/asm-nios2nommu/uaccess.h b/include/asm-nios2nommu/uaccess.h new file mode 100644 index 00000000..0ef67349 --- /dev/null +++ b/include/asm-nios2nommu/uaccess.h @@ -0,0 +1,183 @@ +#ifndef __NIOS2NOMMU_UACCESS_H +#define __NIOS2NOMMU_UACCESS_H + +/*-------------------------------------------------------------------- + * + * asm-nios2nommu/uaccess.h + * + * User space memory access functions + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Ported from asm-m68knommu/uaccess.h --wentao + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size)) + +static inline int _access_ok(unsigned long addr, unsigned long size) +{ + return (((unsigned long)addr < (unsigned long)nasys_program_mem_end) && + (((unsigned long)addr >= (unsigned long)nasys_program_mem))); +} + +extern inline int verify_area(int type, const void * addr, unsigned long size) +{ + return access_ok(type,addr,size)?0:-EFAULT; +} + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +#define ARCH_HAS_SEARCH_EXTABLE +//;dgt2;tmp; + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); + + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + */ + +#define put_user(x, ptr) \ +({ \ + int __pu_err = 0; \ + typeof(*(ptr)) __pu_val = (x); \ + switch (sizeof (*(ptr))) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + memcpy(ptr, &__pu_val, sizeof (*(ptr))); \ + break; \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + __pu_err; \ +}) +#define __put_user(x, ptr) put_user(x, ptr) + +extern int __put_user_bad(void); + +/* + * Tell gcc we read from memory instead of writing: this is because + * we do not write to any memory gcc knows about, so there are no + * aliasing issues. + */ + +#define __ptr(x) ((unsigned long *)(x)) + +#define get_user(x, ptr) \ +({ \ + int __gu_err = 0; \ + typeof(*(ptr)) __gu_val = 0; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + case 2: \ + case 4: \ + case 8: \ + memcpy(&__gu_val, ptr, sizeof (*(ptr))); \ + break; \ + default: \ + __gu_val = 0; \ + __gu_err = __get_user_bad(); \ + break; \ + } \ + (x) = __gu_val; \ + __gu_err; \ +}) +#define __get_user(x, ptr) get_user(x, ptr) + +extern int __get_user_bad(void); + +#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) +#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) + +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) + +#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) + +/* + * Copy a null terminated string from userspace. + */ + +static inline long +strncpy_from_user(char *dst, const char *src, long count) +{ + char *tmp; + strncpy(dst, src, count); + for (tmp = dst; *tmp && count > 0; tmp++, count--) + ; + return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */ +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +static inline long strnlen_user(const char *src, long n) +{ + return(strlen(src) + 1); /* DAVIDM make safer */ +} + +#define strlen_user(str) strnlen_user(str, 32767) + +/* + * Zero Userspace + */ + +static inline unsigned long +clear_user(void *to, unsigned long n) +{ + memset(to, 0, n); + return(0); +} + +#endif /* _NIOS2NOMMU_UACCESS_H */ diff --git a/include/asm-nios2nommu/uart_struct.h b/include/asm-nios2nommu/uart_struct.h new file mode 100644 index 00000000..d9551924 --- /dev/null +++ b/include/asm-nios2nommu/uart_struct.h @@ -0,0 +1,83 @@ + +// UART Registers +typedef volatile struct + { + int np_uartrxdata; // Read-only, 8-bit + int np_uarttxdata; // Write-only, 8-bit + int np_uartstatus; // Read-only, 8-bit + int np_uartcontrol; // Read/Write, 9-bit + int np_uartdivisor; // Read/Write, 16-bit, optional + int np_uartendofpacket; // Read/Write, end-of-packet character + } np_uart; + +// UART Status Register Bits +enum + { + np_uartstatus_eop_bit = 12, + np_uartstatus_cts_bit = 11, + np_uartstatus_dcts_bit = 10, + np_uartstatus_e_bit = 8, + np_uartstatus_rrdy_bit = 7, + np_uartstatus_trdy_bit = 6, + np_uartstatus_tmt_bit = 5, + np_uartstatus_toe_bit = 4, + np_uartstatus_roe_bit = 3, + np_uartstatus_brk_bit = 2, + np_uartstatus_fe_bit = 1, + np_uartstatus_pe_bit = 0, + + np_uartstatus_eop_mask = (1<<12), + np_uartstatus_cts_mask = (1<<11), + np_uartstatus_dcts_mask = (1<<10), + np_uartstatus_e_mask = (1<<8), + np_uartstatus_rrdy_mask = (1<<7), + np_uartstatus_trdy_mask = (1<<6), + np_uartstatus_tmt_mask = (1<<5), + np_uartstatus_toe_mask = (1<<4), + np_uartstatus_roe_mask = (1<<3), + np_uartstatus_brk_mask = (1<<2), + np_uartstatus_fe_mask = (1<<1), + np_uartstatus_pe_mask = (1<<0) + }; + +// UART Control Register Bits +enum + { + np_uartcontrol_ieop_bit = 12, + np_uartcontrol_rts_bit = 11, + np_uartcontrol_idcts_bit = 10, + np_uartcontrol_tbrk_bit = 9, + np_uartcontrol_ie_bit = 8, + np_uartcontrol_irrdy_bit = 7, + np_uartcontrol_itrdy_bit = 6, + np_uartcontrol_itmt_bit = 5, + np_uartcontrol_itoe_bit = 4, + np_uartcontrol_iroe_bit = 3, + np_uartcontrol_ibrk_bit = 2, + np_uartcontrol_ife_bit = 1, + np_uartcontrol_ipe_bit = 0, + + np_uartcontrol_ieop_mask = (1<<12), + np_uartcontrol_rts_mask = (1<<11), + np_uartcontrol_idcts_mask = (1<<10), + np_uartcontrol_tbrk_mask = (1<<9), + np_uartcontrol_ie_mask = (1<<8), + np_uartcontrol_irrdy_mask = (1<<7), + np_uartcontrol_itrdy_mask = (1<<6), + np_uartcontrol_itmt_mask = (1<<5), + np_uartcontrol_itoe_mask = (1<<4), + np_uartcontrol_iroe_mask = (1<<3), + np_uartcontrol_ibrk_mask = (1<<2), + np_uartcontrol_ife_mask = (1<<1), + np_uartcontrol_ipe_mask = (1<<0) + }; + +// UART Routines +int nr_uart_rxchar(np_uart *uartBase); // 0 for default UART +void nr_uart_txcr(void); +void nr_uart_txchar(int c,np_uart *uartBase); // 0 for default UART +void nr_uart_txhex(int x); // 16 or 32 bits +void nr_uart_txhex16(short x); +void nr_uart_txhex32(long x); +void nr_uart_txstring(char *s); + diff --git a/include/asm-nios2nommu/ucontext.h b/include/asm-nios2nommu/ucontext.h new file mode 100644 index 00000000..f2e7ce2b --- /dev/null +++ b/include/asm-nios2nommu/ucontext.h @@ -0,0 +1,63 @@ +#ifndef _NIOSKNOMMU_UCONTEXT_H +#define _NIOSKNOMMU_UCONTEXT_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/ucontext.h + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +typedef int greg_t; +#define NGREG 32 +typedef greg_t gregset_t[NGREG]; + +#ifdef CONFIG_FPU +typedef struct fpregset { + int f_pcr; + int f_psr; + int f_fpiaddr; + int f_fpregs[8][3]; +} fpregset_t; +#endif + +struct mcontext { + int version; + int status_extension; + gregset_t gregs; +#ifdef CONFIG_FPU + fpregset_t fpregs; +#endif +}; + +#define MCONTEXT_VERSION 2 + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct mcontext uc_mcontext; +#ifdef CONFIG_FPU + unsigned long uc_filler[80]; +#endif + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif diff --git a/include/asm-nios2nommu/unaligned.h b/include/asm-nios2nommu/unaligned.h new file mode 100644 index 00000000..48761852 --- /dev/null +++ b/include/asm-nios2nommu/unaligned.h @@ -0,0 +1,6 @@ +#ifndef __NIOS2_UNALIGNED_H +#define __NIOS2_UNALIGNED_H + +#include + +#endif /* __NIOS2_UNALIGNED_H */ diff --git a/include/asm-nios2nommu/unistd.h b/include/asm-nios2nommu/unistd.h new file mode 100644 index 00000000..248ce0a2 --- /dev/null +++ b/include/asm-nios2nommu/unistd.h @@ -0,0 +1,694 @@ +#ifndef _ASM_NIOS_UNISTD_H_ +#define _ASM_NIOS_UNISTD_H_ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/unistd.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * //vic - kernel_thread moved to process.c + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +/* TRAP isr expects the trap# (syscall=#TRAP_ID_SYSCALL) in r2, + * the syscall # in r3, and arguments in r4, r5, ... + * Return argument expected in r2. + */ + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 //vic #define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl /* 110 */ not supported +#define __NR_vhangup 111 +#define __NR_idle /* 112 */ Obsolete +#define __NR_vm86 /* 113 */ not supported +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_cacheflush 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_getpagesize 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 /* some people actually want streams */ +#define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_chown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_lchown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_getdents64 220 +#define __NR_fcntl64 221 +#define __NR_security 223 +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_alloc_hugepages 250 +#define __NR_free_hugepages 251 +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_sys_epoll_create 254 +#define __NR_sys_epoll_ctl 255 +#define __NR_sys_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 +#define __NR_tgkill 270 +#define __NR_utimes 271 +#define __NR_fadvise64_64 272 +#define __NR_vserver 273 +#define __NR_mbind 274 +#define __NR_get_mempolicy 275 +#define __NR_set_mempolicy 276 +#define __NR_mq_open 277 +#define __NR_mq_unlink (__NR_mq_open+1) +#define __NR_mq_timedsend (__NR_mq_open+2) +#define __NR_mq_timedreceive (__NR_mq_open+3) +#define __NR_mq_notify (__NR_mq_open+4) +#define __NR_mq_getsetattr (__NR_mq_open+5) +#define __NR_sys_kexec_load 283 +#define __NR_waitid 284 +/* #define __NR_sys_setaltroot 285 */ +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 + +#define NR_syscalls 289 + + +/* user-visible error numbers are in the range -1 - -122: see + */ + +#define __syscall_return(type, res) \ +do { \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + \ + /* avoid using res which is declared to be in \ + register r2; errno might expand to a function \ + call and clobber it. */ \ + \ + int __err = -(res); \ + errno = __err; \ + res = -1; \ + } \ + return (type) (res); \ +} while (0) + +#define _syscall0(type,name) \ +type name(void) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall1 arg a +//;dgt2;tmp; already being in r4 ? +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall2 args a,b +//;dgt2;tmp; already being in r4,r5 ? +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + " mov r5, %4\n\t" /* (long) b */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + , "r" ((long) b) /* %4 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + , "r5" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall3 args a,b,c +//;dgt2;tmp; already being in r4,r5,r6 ? +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + " mov r5, %4\n\t" /* (long) b */ \ + " mov r6, %5\n\t" /* (long) c */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + , "r" ((long) b) /* %4 */ \ + , "r" ((long) c) /* %5 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + , "r5" /* Clobbered */ \ + , "r6" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall4 args a,b,c,d +//;dgt2;tmp; already being in r4,r5,r6,r7 ? +#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ +type name (atype a, btype b, ctype c, dtype d) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + " mov r5, %4\n\t" /* (long) b */ \ + " mov r6, %5\n\t" /* (long) c */ \ + " mov r7, %6\n\t" /* (long) d */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + , "r" ((long) b) /* %4 */ \ + , "r" ((long) c) /* %5 */ \ + , "r" ((long) d) /* %6 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + , "r5" /* Clobbered */ \ + , "r6" /* Clobbered */ \ + , "r7" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall5 args a,b,c,d +//;dgt2;tmp; already being in r4,r5,r6,r7 ? +#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ +type name (atype a,btype b,ctype c,dtype d,etype e) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + " mov r5, %4\n\t" /* (long) b */ \ + " mov r6, %5\n\t" /* (long) c */ \ + " mov r7, %6\n\t" /* (long) c */ \ + " mov r8, %7\n\t" /* (long) e */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + , "r" ((long) b) /* %4 */ \ + , "r" ((long) c) /* %5 */ \ + , "r" ((long) d) /* %6 */ \ + , "r" ((long) e) /* %7 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + , "r5" /* Clobbered */ \ + , "r6" /* Clobbered */ \ + , "r7" /* Clobbered */ \ + , "r8" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +//;dgt2;tmp;can we RELY on syscall6 args a,b,c,d +//;dgt2;tmp; already being in r4,r5,r6,r7 ? +#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ +type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ +{ \ + long __res; \ + \ + __asm__ __volatile__ ( \ + \ + " \n\t" \ + \ + " movi r2, %2\n\t" /* TRAP_ID_SYSCALL */ \ + " movi r3, %1\n\t" /* __NR_##name */ \ + " mov r4, %3\n\t" /* (long) a */ \ + " mov r5, %4\n\t" /* (long) b */ \ + " mov r6, %5\n\t" /* (long) c */ \ + " mov r7, %6\n\t" /* (long) c */ \ + " mov r8, %7\n\t" /* (long) e */ \ + " mov r9, %8\n\t" /* (long) f */ \ + \ + " trap\n\t" \ + " mov %0, r2\n\t" /* syscall rtn */ \ + \ + " \n\t" \ + \ + : "=r" (__res) /* %0 */ \ + \ + : "i" (__NR_##name) /* %1 */ \ + , "i" (TRAP_ID_SYSCALL) /* %2 */ \ + , "r" ((long) a) /* %3 */ \ + , "r" ((long) b) /* %4 */ \ + , "r" ((long) c) /* %5 */ \ + , "r" ((long) d) /* %6 */ \ + , "r" ((long) e) /* %7 */ \ + , "r" ((long) f) /* %8 */ \ + \ + : "r2" /* Clobbered */ \ + , "r3" /* Clobbered */ \ + , "r4" /* Clobbered */ \ + , "r5" /* Clobbered */ \ + , "r6" /* Clobbered */ \ + , "r7" /* Clobbered */ \ + , "r8" /* Clobbered */ \ + , "r9" /* Clobbered */ \ + ); \ + \ +__syscall_return(type,__res); \ +} + +#ifdef __KERNEL__ +#define __ARCH_WANT_IPC_PARSE_VERSION +#define __ARCH_WANT_OLD_READDIR +#define __ARCH_WANT_OLD_STAT +#define __ARCH_WANT_STAT64 +#define __ARCH_WANT_SYS_ALARM +#define __ARCH_WANT_SYS_GETHOSTNAME +#define __ARCH_WANT_SYS_PAUSE +#define __ARCH_WANT_SYS_SGETMASK +#define __ARCH_WANT_SYS_SIGNAL +#define __ARCH_WANT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_WAITPID +#define __ARCH_WANT_SYS_SOCKETCALL +#define __ARCH_WANT_SYS_FADVISE64 +#define __ARCH_WANT_SYS_GETPGRP +#define __ARCH_WANT_SYS_LLSEEK +#define __ARCH_WANT_SYS_NICE +#define __ARCH_WANT_SYS_OLD_GETRLIMIT +#define __ARCH_WANT_SYS_OLDUMOUNT +#define __ARCH_WANT_SYS_SIGPENDING +#define __ARCH_WANT_SYS_SIGPROCMASK +#define __ARCH_WANT_SYS_RT_SIGACTION +#endif + +#ifdef __KERNEL_SYSCALLS__ + +#include +#include + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +static inline _syscall0(int,pause) +static inline _syscall0(int,sync) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall1(int,delete_module,const char *,name) + +static inline pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + +#endif + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); + +#endif /* _ASM_NIOS_UNISTD_H_ */ diff --git a/include/asm-nios2nommu/user.h b/include/asm-nios2nommu/user.h new file mode 100644 index 00000000..3cdc2ba5 --- /dev/null +++ b/include/asm-nios2nommu/user.h @@ -0,0 +1,112 @@ +#ifndef _NIOS2NOMMU_USER_H +#define _NIOS2NOMMU_USER_H + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/user.h + * + * Derived from M68knommu + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +#include + +/* Core file format: The core file is written in such a way that gdb + can understand it and provide useful information to the user (under + linux we use the 'trad-core' bfd). There are quite a number of + obstacles to being able to view the contents of the floating point + registers, and until these are solved you will not be able to view the + contents of them. Actually, you can read in the core file and look at + the contents of the user struct to find out what the floating point + registers contain. + The actual file contents are as follows: + UPAGE: 1 page consisting of a user struct that tells gdb what is present + in the file. Directly after this is a copy of the task_struct, which + is currently not used by gdb, but it may come in useful at some point. + All of the registers are stored as part of the upage. The upage should + always be only one page. + DATA: The data area is stored. We use current->end_text to + current->brk to pick up all of the user variables, plus any memory + that may have been malloced. No attempt is made to determine if a page + is demand-zero or if a page is totally unused, we just cover the entire + range. All of the addresses are rounded in such a way that an integral + number of pages is written. + STACK: We need the stack information in order to get a meaningful + backtrace. We need to write the data from (esp) to + current->start_stack, so we round each of these off in order to be able + to write an integer number of pages. + The minimum core file size is 3 pages, or 12288 bytes. +*/ + +struct user_m68kfp_struct { + unsigned long fpregs[8*3]; /* fp0-fp7 registers */ + unsigned long fpcntl[3]; /* fp control regs */ +}; + +/* This is needs more work, probably should look like gdb useage */ +struct user_regs_struct { + long r1,r2,r3,r4,r5,r6,r7,r8; + long r9,r10,r11,r12,r13,r14,r15; + long r16,r17,r18,r19,r20,r21,r22,r23; + long gp; + long sp; + long ra; + long fp; + long orig_r2; + long estatus; + long status_extension; + long ea; +}; + + +/* When the kernel dumps core, it starts by dumping the user struct - + this will be used by gdb to figure out where the data and stack segments + are within the file, and what virtual addresses to use. */ +struct user{ +/* We start with the registers, to mimic the way that "memory" is returned + from the ptrace(3,...) function. */ + struct user_regs_struct regs; /* Where the registers are actually stored */ +/* ptrace does not yet supply these. Someday.... */ + int u_fpvalid; /* True if math co-processor being used. */ + /* for this mess. Not yet used. */ + struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */ +/* The rest of this junk is to help gdb figure out what goes where */ + unsigned long int u_tsize; /* Text segment size (pages). */ + unsigned long int u_dsize; /* Data segment size (pages). */ + unsigned long int u_ssize; /* Stack segment size (pages). */ + unsigned long start_code; /* Starting virtual address of text. */ + unsigned long start_stack; /* Starting virtual address of stack area. + This is actually the bottom of the stack, + the top of the stack is always found in the + esp register. */ + long int signal; /* Signal that caused the core dump. */ + int reserved; /* No longer used */ + struct user_regs_struct *u_ar0; + /* Used by gdb to help find the values for */ + /* the registers. */ + struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */ + unsigned long magic; /* To uniquely identify a core file */ + char u_comm[32]; /* User command that was responsible */ +}; +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif diff --git a/include/asm-nios2nommu/virtconvert.h b/include/asm-nios2nommu/virtconvert.h new file mode 100644 index 00000000..89bf899e --- /dev/null +++ b/include/asm-nios2nommu/virtconvert.h @@ -0,0 +1,46 @@ +#ifndef __NIOS_VIRT_CONVERT__ +#define __NIOS_VIRT_CONVERT__ + +/*-------------------------------------------------------------------- + * + * include/asm-nios2nommu/virtconvert.h + * + * Derived from various works, Alpha, ix86, M68K, Sparc, ...et al + * + * Copyright (C) 2004 Microtronix Datacom 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. + * + * + * Jan/20/2004 dgt NiosII + * + ---------------------------------------------------------------------*/ + + +/* + * Macros used for converting between virtual and physical mappings. + */ + +#ifdef __KERNEL__ + +#include +#include + +#define mm_ptov(vaddr) ((void *) (vaddr)) +#define mm_vtop(vaddr) ((unsigned long) (vaddr)) +#define phys_to_virt(vaddr) ((void *) (vaddr)) +#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + +#endif /*__KERNEL__ */ +#endif /*__NIOS_VIRT_CONVERT__*/ diff --git a/include/asm-sh/fast_timer.h b/include/asm-sh/fast_timer.h new file mode 100644 index 00000000..84ccedb5 --- /dev/null +++ b/include/asm-sh/fast_timer.h @@ -0,0 +1,104 @@ +#ifndef __ASM_SH_FAST_TIMER_H +#define __ASM_SH_FAST_TIMER_H + +#include +#include +#include +#include + +#define FAST_POLL_INTR + +#define FASTTIMER_IRQ 17 +#define FASTTIMER_IPR_ADDR INTC_IPRA +#define FASTTIMER_IPR_POS 2 +#define FASTTIMER_PRIORITY 3 + +#ifdef FAST_POLL_INTR +#define TMU1_TCR_INIT 0x0020 +#else +#define TMU1_TCR_INIT 0 +#endif +#define TMU_TSTR_INIT 1 +#define TMU1_TCR_CALIB 0x0000 +#define TMU_TOCR 0xffd80000 /* Byte access */ +#define TMU_TSTR 0xffd80004 /* Byte access */ +#define TMU1_TCOR 0xffd80014 /* Long access */ +#define TMU1_TCNT 0xffd80018 /* Long access */ +#define TMU1_TCR 0xffd8001c /* Word access */ + +static irqreturn_t +fast_timer_interrupt(int irq, void *dev_id) +{ + unsigned long timer_status; + + timer_status = ctrl_inw(TMU1_TCR); + timer_status &= ~0x100; + ctrl_outw(timer_status, TMU1_TCR); + + do_fast_timer(); + return IRQ_HANDLED; +} + +static void fast_timer_set(void) +{ + unsigned long interval; + struct clk *clk = clk_get("module_clk"); + +#ifdef FAST_POLL_INTR + if (clk) { + interval = (clk_get_rate(clk)/4 + fast_timer_rate/2) / fast_timer_rate; + } else +#endif + interval = 0xffffffff; + + ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */ + ctrl_outw(TMU1_TCR_INIT, TMU1_TCR); + ctrl_outl(interval, TMU1_TCOR); + ctrl_outl(interval, TMU1_TCNT); + ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */ +} + +static int __init fast_timer_setup(void) +{ +#ifdef FAST_POLL_INTR + static struct ipr_data fast_timer_ipr_map[] = { + { FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS, FASTTIMER_PRIORITY}, + }; + + make_ipr_irq(fast_timer_ipr_map, ARRAY_SIZE(fast_timer_ipr_map)); + + if (request_irq(FASTTIMER_IRQ, fast_timer_interrupt, SA_INTERRUPT, + "fast timer", NULL)) + return -EBUSY; +#endif + + fast_timer_rate = cpu_data->type == CPU_SH7751R ? 2000 : 1000; + fast_timer_set(); + +#ifdef FAST_POLL_INTR + printk("fast timer: %d Hz, IRQ %d\n", fast_timer_rate, + FASTTIMER_IRQ); +#else + printk("fast timer: %d Hz\n", fast_timer_rate); +#endif + return 0; +} + +static void __exit fast_timer_cleanup(void) +{ + ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */ + free_irq(FASTTIMER_IRQ, NULL); +} + +#if 0 +/* + * return the current ticks on the fast timer + */ + +unsigned long fast_timer_count(void) +{ + return(ctrl_inl(TMU1_TCNT)); +} +#endif + +#endif diff --git a/include/asm-sh/namei.h b/include/asm-sh/namei.h index 338a5d94..a5672fc6 100644 --- a/include/asm-sh/namei.h +++ b/include/asm-sh/namei.h @@ -1,4 +1,4 @@ -/* $Id: namei.h,v 1.3 2000/07/04 06:24:49 gniibe Exp $ +/* $Id: namei.h,v 1.1.1.1 2001/10/15 20:45:10 mrbrown Exp $ * linux/include/asm-sh/namei.h * * Included from linux/fs/namei.c diff --git a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h index ed358a37..a6f3b7c4 100644 --- a/include/asm-sh/ptrace.h +++ b/include/asm-sh/ptrace.h @@ -85,6 +85,7 @@ struct pt_dspregs { #define PTRACE_SETDSPREGS 56 #ifdef __KERNEL__ +#define user_stack(regs) ((regs)->regs[15]) #define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define instruction_pointer(regs) ((regs)->pc) extern void show_regs(struct pt_regs *); diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h index 57abd708..84b430e9 100644 --- a/include/asm-sh/sections.h +++ b/include/asm-sh/sections.h @@ -3,7 +3,7 @@ #include -extern char _end[]; +extern char _end[], __initramfs_end[]; #endif /* __ASM_SH_SECTIONS_H */ diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h index 6b5e4ddc..57d97540 100644 --- a/include/asm-sh/snapgear.h +++ b/include/asm-sh/snapgear.h @@ -1,5 +1,5 @@ /* - * include/asm-sh/snapgear/io.h + * include/asm-sh/snapgear.h * * Modified version of io_se.h for the snapgear-specific functions. * @@ -38,6 +38,11 @@ #define IRL3_IPR_ADDR INTC_IPRD #define IRL3_IPR_POS 0 #define IRL3_PRIORITY 4 + +#define RTC_BASE 0xffc80000 +#define RTC_ATI_IRQ 20 +#define RTC_PRI_IRQ 21 +#define RTC_CUI_IRQ 22 #endif #define __IO_PREFIX snapgear diff --git a/include/asm-um/param.h b/include/asm-um/param.h index f914e7d6..61636aee 100644 --- a/include/asm-um/param.h +++ b/include/asm-um/param.h @@ -15,4 +15,8 @@ #define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */ #endif +#ifndef HZ +#define HZ 100 +#endif + #endif diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 7bfcde2d..ff896274 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -261,7 +261,11 @@ struct request { union { struct rb_node rb_node; /* sort/lookup */ void *completion_data; +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } u; +#endif /* * two pointers are available for the IO schedulers, if they need diff --git a/include/linux/compiler-gcc+.h b/include/linux/compiler-gcc+.h new file mode 100644 index 00000000..6b930854 --- /dev/null +++ b/include/linux/compiler-gcc+.h @@ -0,0 +1,16 @@ +/* Never include this file directly. Include instead. */ + +/* + * These definitions are for Ueber-GCC: always newer than the latest + * version and hence sporting everything plus a kitchen-sink. + */ +#include + +#define inline inline __attribute__((always_inline)) +#define __inline__ __inline__ __attribute__((always_inline)) +#define __inline __inline __attribute__((always_inline)) +#define __deprecated __attribute__((deprecated)) +#define __attribute_used__ __attribute__((__used__)) +#define __attribute_pure__ __attribute__((pure)) +#define __attribute_const__ __attribute__((__const__)) +#define __must_check __attribute__((warn_unused_result)) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 6e1c44a9..c47d8a3d 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -23,6 +23,7 @@ (typeof(ptr)) (__ptr + (off)); }) +#if 0 // mask by Victor Yu. 02-12-2007 #define inline inline __attribute__((always_inline)) #define __inline__ __inline__ __attribute__((always_inline)) #define __inline __inline __attribute__((always_inline)) @@ -30,3 +31,4 @@ #define noinline __attribute__((noinline)) #define __attribute_pure__ __attribute__((pure)) #define __attribute_const__ __attribute__((__const__)) +#endif diff --git a/include/linux/compiler-gcc2.h b/include/linux/compiler-gcc2.h new file mode 100644 index 00000000..5a359153 --- /dev/null +++ b/include/linux/compiler-gcc2.h @@ -0,0 +1,24 @@ +/* Never include this file directly. Include instead. */ + +/* These definitions are for GCC v2.x. */ + +/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented + a mechanism by which the user can annotate likely branch directions and + expect the blocks to be reordered appropriately. Define __builtin_expect + to nothing for earlier compilers. */ +#include + +#if __GNUC_MINOR__ < 96 +# define __builtin_expect(x, expected_value) (x) +#endif + +#define __attribute_used__ __attribute__((__unused__)) + +/* + * The attribute `pure' is not implemented in GCC versions earlier + * than 2.96. + */ +#if __GNUC_MINOR__ >= 96 +# define __attribute_pure__ __attribute__((pure)) +# define __attribute_const__ __attribute__((__const__)) +#endif diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h index 1698b845..5b87489a 100644 --- a/include/linux/compiler-gcc3.h +++ b/include/linux/compiler-gcc3.h @@ -14,3 +14,15 @@ #endif #define __always_inline inline __attribute__((always_inline)) + +#if __GNUC_MINOR__ <= 0 +#undef __always_inline +#define __always_inline inline +#undef inline +#undef __inline__ +#undef __inline +#undef __deprecated +#define __deprecated +#undef noinline +#define noinline +#endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 538423d4..1b61a321 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -42,6 +42,8 @@ extern void __chk_io_ptr(void __iomem *); # include #elif __GNUC__ == 3 # include +#elif __GNUC__ == 2 +# include #else # error Sorry, your compiler is too old/not recognized. #endif diff --git a/include/linux/config.h b/include/linux/config.h new file mode 120000 index 00000000..62675db0 --- /dev/null +++ b/include/linux/config.h @@ -0,0 +1 @@ +autoconf.h \ No newline at end of file diff --git a/include/linux/dm270-id.h b/include/linux/dm270-id.h new file mode 100644 index 00000000..5698caf6 --- /dev/null +++ b/include/linux/dm270-id.h @@ -0,0 +1,106 @@ +/* FIXME: this temporarily, until these are included in linux/video_decoder.h */ +struct video_decoder_reg +{ + unsigned short addr; + unsigned char val; +}; + +#define DM270V4L_IMGSIZE_SUBQCIF_WIDTH 128 +#define DM270V4L_IMGSIZE_SUBQCIF_HEIGHT 96 +#define DM270V4L_IMGSIZE_QQVGA_WIDTH 160 +#define DM270V4L_IMGSIZE_QQVGA_HEIGHT 120 +#define DM270V4L_IMGSIZE_QCIF_WIDTH 176 +#define DM270V4L_IMGSIZE_QCIF_HEIGHT 144 +#define DM270V4L_IMGSIZE_QVGA_WIDTH 320 +#define DM270V4L_IMGSIZE_QVGA_HEIGHT 240 +#define DM270V4L_IMGSIZE_CIF_WIDTH 352 +#define DM270V4L_IMGSIZE_CIF_HEIGHT 288 +#define DM270V4L_IMGSIZE_VGA_WIDTH 640 +#define DM270V4L_IMGSIZE_VGA_HEIGHT 480 +#define DM270V4L_IMGSIZE_NTSC_WIDTH 720 +#define DM270V4L_IMGSIZE_NTSC_HEIGHT 480 + +/* FIXME: this temporarily, until these are included in linux/fb.h */ +#define FBIOPUT_DM270_COLORIMG 0x4680 +#define FBCMD_DM270_PRINT_FBUF 0x468e +#define FBCMD_DM270_PRINT_REG 0x468f + +/* FIXME: this temporarily, until these are included in linux/i2c-id.h */ +/* sensor/video decoder chips */ +#ifndef I2C_DRIVERID_STV0974 +# define I2C_DRIVERID_STV0974 I2C_DRIVERID_EXP0 +#endif +#ifndef I2C_DRIVERID_MT9V111 +# define I2C_DRIVERID_MT9V111 I2C_DRIVERID_EXP1 +#endif +#ifndef I2C_DRIVERID_TCM8210MDA +# define I2C_DRIVERID_TCM8210MDA I2C_DRIVERID_EXP2 +#endif +#ifndef I2C_DRIVERID_SAA7113 +# define I2C_DRIVERID_SAA7113 I2C_DRIVERID_EXP3 +#endif +#ifndef I2C_DRIVERID_TVP5150A +# define I2C_DRIVERID_TVP5150A (I2C_DRIVERID_EXP0 + 4) +#endif + +#ifndef GPIO_DRIVERID_4T103X3M +# define GPIO_DRIVERID_4T103X3M (I2C_DRIVERID_EXP0 + 5) +#endif + +/* video encoder chips */ +#ifndef MMIO_DRIVERID_DM270VENC +# define MMIO_DRIVERID_DM270VENC (I2C_DRIVERID_EXP0 + 8) +#endif + +/* FIXME: this temporarily, until these are included in linux/videodev2.h */ +#ifndef V4L2_PIX_FMT_MPEG4 +# define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M','P','G','4') /* MPEG4 */ +#endif + +/* FIXME: this temporarily, until these are included in linux/videodev2.h */ +#ifndef V4L2_PIX_FMT_H263 +# define V4L2_PIX_FMT_H263 v4l2_fourcc('H','2','6','3') /* H.263 */ +#endif + +/* FIXME: this temporarily, until these are included in linux/video_decoder.h */ +#ifndef DECODER_GET_FIELD +# define DECODER_GET_FIELD _IOR('d', 128, int) +#endif +#ifndef DECODER_SET_CROP +# define DECODER_SET_CROP _IOW('d', 129, struct v4l2_crop) +#endif +#ifndef DECODER_SET_FMT +# define DECODER_SET_FMT _IOW('d', 130, struct v4l2_format) +#endif +#ifndef DECODER_INIT +# define DECODER_INIT _IOW('d', 131, int) +#endif +#ifndef DECODER_REG_READ +# define DECODER_REG_READ _IOWR('d', 132, struct video_decoder_reg) +#endif +#ifndef DECODER_REG_WRITE +# define DECODER_REG_WRITE _IOW('d', 133, struct video_decoder_reg) +#endif + +/* FIXME: this temporarily, until these are included in linux/videodev2.h */ +#ifndef VIDIOC_S_CAMERAPWR +# define VIDIOC_S_CAMERAPWR _IOW('v', BASE_VIDIOCPRIVATE+4, int) +#endif +#ifndef VIDIOC_DBGPRINT +# define VIDIOC_DBGPRINT _IOW('v', BASE_VIDIOCPRIVATE+7, int) +#endif +#ifndef VIDIOC_PRTCAPTURE +# define VIDIOC_PRTCAPTURE _IOW('v', BASE_VIDIOCPRIVATE+8, int) +#endif +#ifndef VIDIOC_PRTOUTPUT +# define VIDIOC_PRTOUTPUT _IOW('v', BASE_VIDIOCPRIVATE+9, int) +#endif +#ifndef VIDIOC_PRTOVERLAY +# define VIDIOC_PRTOVERLAY _IOW('v', BASE_VIDIOCPRIVATE+10, int) +#endif +#ifndef VIDIOC_G_DECREG +# define VIDIOC_G_DECREG _IOWR('v', BASE_VIDIOCPRIVATE+11, struct video_decoder_reg) +#endif +#ifndef VIDIOC_S_DECREG +# define VIDIOC_S_DECREG _IOW('v', BASE_VIDIOCPRIVATE+12, struct video_decoder_reg) +#endif diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2fa9f114..03cd1ab4 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -167,7 +167,11 @@ enum { }; #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) +#if 0 // mask by Victor Yu. 02-12-2007 #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) +#else +#define rb_entry_rq(node) rb_entry((node), struct request, u.rb_node) +#endif /* * Hack to reuse the donelist list_head as the fifo time holder while diff --git a/include/linux/fast_timer.h b/include/linux/fast_timer.h new file mode 100644 index 00000000..117b00da --- /dev/null +++ b/include/linux/fast_timer.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_FAST_TIMER_H +#define _LINUX_FAST_TIMER_H + +extern void fast_timer_add(void (*func)(void *arg), void *arg); +extern void fast_timer_remove(void (*func)(void *arg), void *arg); +extern unsigned long fast_timer_count(void); + +#endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 2fe6e3f9..578d65a4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -573,7 +573,11 @@ struct inode { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } u; +#endif int i_cindex; __u32 i_generation; diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 0a8f750c..bb9a3a1c 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -200,6 +200,9 @@ #define I2C_HW_P_ISA 0x020001 /* generic ISA Bus inteface card */ #define I2C_HW_P_ELEK 0x020002 /* Elektor ISA Bus inteface card */ +/* --- Opencores I2C based adaptors */ +#define I2C_HW_OC_UKIT 0x180000 /* what is on Microtronix uKit */ + /* --- PCA 9564 based algorithms */ #define I2C_HW_A_ISA 0x1a0000 /* generic ISA Bus interface card */ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index fd1b6eb9..935a51d2 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -107,6 +107,7 @@ struct __fdb_entry extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *)); extern int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb); extern int (*br_should_route_hook)(struct sk_buff **pskb); +extern void br_stp_rcv_raw(struct sk_buff *skb, struct net_device *dev); #endif diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index ab08f35c..fd04b190 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -55,6 +55,7 @@ #define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ #define ETH_P_CUST 0x6006 /* DEC Customer use */ #define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ +#define ETH_P_BRIDGE 0x6558 /* Transparent Ethernet Bridging */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ #define ETH_P_ATALK 0x809B /* Appletalk DDP */ #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b9b5e4ba..6e85323d 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -173,8 +173,13 @@ __attribute_const__ roundup_pow_of_two(unsigned long x) extern int printk_ratelimit(void); extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); +#if 0 // mask by Victor Yu. 02-12-2007 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msec); +#else +extern int printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msec); +#endif static inline void console_silent(void) { diff --git a/include/linux/ledman.h b/include/linux/ledman.h new file mode 100644 index 00000000..a703e0d9 --- /dev/null +++ b/include/linux/ledman.h @@ -0,0 +1,109 @@ +#ifndef __LINUX_LEDMAN_H__ +#define __LINUX_LEDMAN_H__ 1 +/****************************************************************************/ +/* + * ledman.h: LED manager header, generic, device indepedant LED stuff + * + * defines for led functionality which may/may not be implemented by the + * currently active LED configuration + * + * NOTE: do not change the numbering of the defines below, tables of + * LED patterns rely on these values + */ + +#include + +#define LEDMAN_ALL 0 /* special case, all LED's */ + +#define LEDMAN_POWER 1 +#define LEDMAN_HEARTBEAT 2 +#define LEDMAN_COM1_RX 3 +#define LEDMAN_COM1_TX 4 +#define LEDMAN_COM2_RX 5 +#define LEDMAN_COM2_TX 6 +#define LEDMAN_LAN1_RX 7 +#define LEDMAN_LAN1_TX 8 +#define LEDMAN_LAN2_RX 9 +#define LEDMAN_LAN2_TX 10 +#define LEDMAN_USB1_RX 11 +#define LEDMAN_USB1_TX 12 +#define LEDMAN_USB2_RX 13 +#define LEDMAN_USB2_TX 14 +#define LEDMAN_NVRAM_1 15 +#define LEDMAN_NVRAM_2 16 +#define LEDMAN_VPN 17 +#define LEDMAN_LAN1_DHCP 18 +#define LEDMAN_LAN2_DHCP 19 +#define LEDMAN_COM1_DCD 20 +#define LEDMAN_COM2_DCD 21 +#define LEDMAN_ONLINE 22 +#define LEDMAN_LAN1_LINK 23 +#define LEDMAN_LAN2_LINK 24 +#define LEDMAN_VPN_RX 25 +#define LEDMAN_VPN_TX 26 +#define LEDMAN_RESET 27 +#define LEDMAN_STATIC 28 +#define LEDMAN_LAN3_RX 29 +#define LEDMAN_LAN3_TX 30 +#define LEDMAN_LAN3_LINK 31 +#define LEDMAN_LAN3_DHCP 32 +#define LEDMAN_FAILOVER 33 +#define LEDMAN_HIGHAVAIL 34 +#define LEDMAN_MAX 35 /* one more than the highest LED above */ + +#define LEDMAN_MAX_NAME 16 + +/****************************************************************************/ +/* + * ioctl cmds + */ + +#define LEDMAN_CMD_SET 0x01 /* turn on briefly to show activity */ +#define LEDMAN_CMD_ON 0x02 /* turn LED on permanently */ +#define LEDMAN_CMD_OFF 0x03 /* turn LED off permanently */ +#define LEDMAN_CMD_FLASH 0x04 /* flash this LED */ +#define LEDMAN_CMD_RESET 0x05 /* reset LED to default behaviour */ + +#define LEDMAN_CMD_ALT_ON 0x06 /* LED is being used for non-std reasons */ +#define LEDMAN_CMD_ALT_OFF 0x07 /* LED is being used for std reasons */ + +#define LEDMAN_CMD_MODE 0x80 /* set LED to named mode (led=char *) */ +#define LEDMAN_CMD_STARTTIMER 0x81 /* enable and init the ledman driver */ +#define LEDMAN_CMD_KILLTIMER 0x82 /* disable the ledman driver */ + +#define LEDMAN_CMD_SIGNAL 0x100 /* pid of process to signal on reset */ + +#define LEDMAN_CMD_ALTBIT 0x8000 /* operate on alternate LED settings */ + +/****************************************************************************/ + +#define LEDMAN_MAJOR 126 + +/****************************************************************************/ +#ifdef __KERNEL__ + +#if LINUX_VERSION_CODE < 0x020100 +extern int ledman_init(void); +#endif + +extern int ledman_setup(char *arg); +extern void ledman_killtimer(void); +extern void ledman_starttimer(void); +extern int ledman_cmd(int cmd, unsigned long led); +extern void ledman_signalreset(void); + +#else + +#include + +#define ledman_cmd(cmd, led) ({ \ + int fd; \ + if ((fd = open("/dev/ledman", O_RDWR)) != -1) { \ + ioctl(fd, cmd, led); \ + close(fd); \ + } \ +}) + +#endif +/****************************************************************************/ +#endif /* __LINUX_LEDMAN_H__ */ diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index b03cfb91..f2531803 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -12,6 +12,7 @@ #define APOLLO_MOUSE_MINOR 7 #define PC110PAD_MINOR 9 /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ +#define CRYPTODEV_MINOR 70 /* /dev/crypto */ #define WATCHDOG_MINOR 130 /* Watchdog timer */ #define TEMP_MINOR 131 /* Temperature Sensor */ #define RTC_MINOR 135 diff --git a/include/linux/mm.h b/include/linux/mm.h index d538de90..48b887b0 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -217,8 +217,13 @@ struct vm_operations_struct { struct mmu_gather; struct inode; +#if 0 // mask by Victor Yu. 02-12-2007 #define page_private(page) ((page)->private) #define set_page_private(page, v) ((page)->private = (v)) +#else +#define page_private(page) ((page)->u.xx.private) +#define set_page_private(page, v) ((page)->u.xx.private = (v)) +#endif /* * FIXME: take this include out, include page-flags.h in @@ -540,7 +545,11 @@ void page_address_init(void); extern struct address_space swapper_space; static inline struct address_space *page_mapping(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif if (unlikely(PageSwapCache(page))) mapping = &swapper_space; @@ -551,7 +560,11 @@ static inline struct address_space *page_mapping(struct page *page) static inline int PageAnon(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0; +#else + return ((unsigned long)page->u.xx.mapping & PAGE_MAPPING_ANON) != 0; +#endif } /* @@ -1007,8 +1020,9 @@ static inline unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long ret = -EINVAL; if ((offset + PAGE_ALIGN(len)) < offset) goto out; - if (!(offset & ~PAGE_MASK)) + if (!(offset & ~PAGE_MASK)) { ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT); + } out: return ret; } diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index c3852fd4..1ab19813 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -39,11 +39,19 @@ struct page { * it points to anon_vma object: * see PAGE_MAPPING_ANON below. */ +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } xx; +#endif #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS spinlock_t ptl; #endif +#if 0 // mask by Victor Yu. 02-12-2007 }; +#else + } u; +#endif pgoff_t index; /* Our offset within mapping. */ struct list_head lru; /* Pageout list, eg. active_list * protected by zone->lru_lock ! diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index a3594dfd..05eeeda2 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -21,6 +21,11 @@ struct mmc_command { u32 arg; u32 resp[4]; unsigned int flags; /* expected response type */ +#if 1 // add by Victor Yu. 03-07-2007 to compatible with 2.6.9 +#define MMC_RSP_SHORT (1 << 0) +#define MMC_RSP_LONG (2 << 0) +#define MMC_RSP_MASK (3 << 0) +#endif #define MMC_RSP_PRESENT (1 << 0) #define MMC_RSP_136 (1 << 1) /* 136 bit response */ #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 9addd073..1207f433 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -80,7 +80,7 @@ * On PPC, it's mmap'd and 16-bit wide. * Others use readb/writeb */ -#if defined(__arm__) +#if defined(__arm__) && !defined(CONFIG_MACH_ESS710) && !defined(CONFIG_MACH_SE5100) #define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) #define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x8000 @@ -88,6 +88,25 @@ #define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) #define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x4000 + +#elif defined(CONFIG_SH_SECUREEDGE5410) + +static inline unsigned char _ReadDOC_(unsigned long adr, int reg) +{ + readb((adr ^ 0x04000000) & 0xf4000000); /* read other flash chip */ + return(readb(((unsigned long)adr)+(reg))); +} + +static inline void _WriteDOC_(unsigned char d, unsigned long adr, int reg) +{ + readb((adr ^ 0x04000000) & 0xf4000000); /* read other flash chip */ + writeb(d, ((unsigned long)adr) + (reg)); +} + +#define ReadDOC_(adr, reg) _ReadDOC_((unsigned long)(adr), (int)(reg)) +#define WriteDOC_(d, adr, reg) _WriteDOC_((unsigned char)(d), (unsigned long)(adr), (int)(reg)) + +#define DOC_IOREMAP_LEN 0x2000 #else #define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg)) #define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(adr) + (reg)) diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h index 9667863b..2160f062 100644 --- a/include/linux/mtd/plat-ram.h +++ b/include/linux/mtd/plat-ram.h @@ -22,10 +22,11 @@ struct platdata_mtd_ram { char *mapname; - char **probes; + const char **probes; struct mtd_partition *partitions; int nr_partitions; int bankwidth; + int root_dev; /* control callbacks */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 64e86803..57b782c6 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -127,6 +127,15 @@ struct ip_conntrack /* Traversed often, so hopefully in different cacheline to top */ /* These are my tuples; original and reply */ struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; + +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + struct { + char * app_proto; /* e.g. "http". NULL before decision. "unknown" after decision if no match */ + char * app_data; /* application layer data so far. NULL after match decision */ + unsigned int app_data_len; + } layer7; +#endif + }; struct ip_conntrack_expect diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 943cc6a4..fada974a 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -24,7 +24,11 @@ struct ip_ct_h323_master { /* Next TPKT length (for separate TPKT header and data) */ u_int16_t tpkt_len[IP_CT_DIR_MAX]; +#if 0 // mask by Victor Yu. 03-03-2007 }; +#else + } victor_union; +#endif }; struct ip_conntrack_expect; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h index 3d4a7737..1fd1cd79 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h @@ -20,9 +20,13 @@ typedef struct TransportAddress { /* CHOICE */ eTransportAddress_nsap, eTransportAddress_nonStandardAddress, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { TransportAddress_ipAddress ipAddress; }; +#else + TransportAddress_ipAddress ipAddress; +#endif } TransportAddress; typedef struct DataProtocolCapability { /* CHOICE */ @@ -61,9 +65,13 @@ typedef struct DataApplicationCapability_application { /* CHOICE */ eDataApplicationCapability_application_t38fax, eDataApplicationCapability_application_genericDataCapability, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { DataProtocolCapability t120; }; +#else + DataProtocolCapability t120; +#endif } DataApplicationCapability_application; typedef struct DataApplicationCapability { /* SEQUENCE */ @@ -83,9 +91,13 @@ typedef struct DataType { /* CHOICE */ eDataType_h235Media, eDataType_multiplexedStream, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { DataApplicationCapability data; }; +#else + DataApplicationCapability data; +#endif } DataType; typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ @@ -103,9 +115,13 @@ typedef struct UnicastAddress { /* CHOICE */ eUnicastAddress_nsap, eUnicastAddress_nonStandardAddress, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { UnicastAddress_iPAddress iPAddress; }; +#else + UnicastAddress_iPAddress iPAddress; +#endif } UnicastAddress; typedef struct H245_TransportAddress { /* CHOICE */ @@ -113,9 +129,13 @@ typedef struct H245_TransportAddress { /* CHOICE */ eH245_TransportAddress_unicastAddress, eH245_TransportAddress_multicastAddress, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { UnicastAddress unicastAddress; }; +#else + UnicastAddress unicastAddress; +#endif } H245_TransportAddress; typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ @@ -152,9 +172,13 @@ typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParam eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { H2250LogicalChannelParameters h2250LogicalChannelParameters; }; +#else + H2250LogicalChannelParameters h2250LogicalChannelParameters; +#endif } OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ @@ -177,9 +201,13 @@ typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParam eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { H2250LogicalChannelParameters h2250LogicalChannelParameters; }; +#else + H2250LogicalChannelParameters h2250LogicalChannelParameters; +#endif } OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ @@ -201,9 +229,13 @@ typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ eNetworkAccessParameters_networkAddress_e164Address, eNetworkAccessParameters_networkAddress_localAreaAddress, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { H245_TransportAddress localAreaAddress; }; +#else + H245_TransportAddress localAreaAddress; +#endif } NetworkAccessParameters_networkAddress; typedef struct NetworkAccessParameters { /* SEQUENCE */ @@ -462,7 +494,11 @@ typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ Information_UUIE information; Facility_UUIE facility; Progress_UUIE progress; +#if 0 // mask by Victor Yu. 03-03-2007 }; +#else + } victor_union; +#endif } H323_UU_PDU_h323_message_body; typedef struct RequestMessage { /* CHOICE */ @@ -483,9 +519,13 @@ typedef struct RequestMessage { /* CHOICE */ eRequestMessage_multilinkRequest, eRequestMessage_logicalChannelRateRequest, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { OpenLogicalChannel openLogicalChannel; }; +#else + OpenLogicalChannel openLogicalChannel; +#endif } RequestMessage; typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ @@ -493,9 +533,13 @@ typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexPa eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { H2250LogicalChannelParameters h2250LogicalChannelParameters; }; +#else + H2250LogicalChannelParameters h2250LogicalChannelParameters; +#endif } OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ @@ -532,10 +576,15 @@ typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE * enum { eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { H2250LogicalChannelAckParameters h2250LogicalChannelAckParameters; }; +#else + H2250LogicalChannelAckParameters + h2250LogicalChannelAckParameters; +#endif } OpenLogicalChannelAck_forwardMultiplexAckParameters; typedef struct OpenLogicalChannelAck { /* SEQUENCE */ @@ -580,9 +629,13 @@ typedef struct ResponseMessage { /* CHOICE */ eResponseMessage_logicalChannelRateAcknowledge, eResponseMessage_logicalChannelRateReject, } choice; +#if 0 // mask by Victor Yu. 03-03-2007 union { OpenLogicalChannelAck openLogicalChannelAck; }; +#else + OpenLogicalChannelAck openLogicalChannelAck; +#endif } ResponseMessage; typedef struct MultimediaSystemControlMessage { /* CHOICE */ @@ -595,7 +648,11 @@ typedef struct MultimediaSystemControlMessage { /* CHOICE */ union { RequestMessage request; ResponseMessage response; +#if 0 // mask by Victor Yu. 03-03-2007 }; +#else + } victor_union; +#endif } MultimediaSystemControlMessage; typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ @@ -935,5 +992,9 @@ typedef struct RasMessage { /* CHOICE */ LocationRequest locationRequest; LocationConfirm locationConfirm; InfoRequestResponse infoRequestResponse; +#if 0 // mask by Victor Yu. 03-03-2007 }; +#else + } victor_union; +#endif } RasMessage; diff --git a/include/linux/netfilter_ipv4/ipt_layer7.h b/include/linux/netfilter_ipv4/ipt_layer7.h new file mode 100644 index 00000000..582d7f30 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_layer7.h @@ -0,0 +1,26 @@ +/* + By Matthew Strait , Dec 2003. + http://l7-filter.sf.net + + 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. + http://www.gnu.org/licenses/gpl.txt +*/ + +#ifndef _IPT_LAYER7_H +#define _IPT_LAYER7_H + +#define MAX_PATTERN_LEN 8192 +#define MAX_PROTOCOL_LEN 256 + +typedef char *(*proc_ipt_search) (char *, char, char *); + +struct ipt_layer7_info { + char protocol[MAX_PROTOCOL_LEN]; + char invert:1; + char pattern[MAX_PATTERN_LEN]; +}; + +#endif /* _IPT_LAYER7_H */ diff --git a/include/linux/netfilter_ipv4/ipt_time.h b/include/linux/netfilter_ipv4/ipt_time.h new file mode 100644 index 00000000..07279b75 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_time.h @@ -0,0 +1,18 @@ +#ifndef __ipt_time_h_included__ +#define __ipt_time_h_included__ + + +struct ipt_time_info { + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ + + /* FIXME: Keep this one for userspace iptables binary compability: */ + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ + + time_t date_start; + time_t date_stop; +}; + + +#endif /* __ipt_time_h_included__ */ diff --git a/include/linux/oom.h b/include/linux/oom.h index ad764636..9db10e41 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -3,6 +3,7 @@ /* /proc//oom_adj set to -17 protects from the oom-killer */ #define OOM_DISABLE (-17) +#define OOM_DISABLE_NOINHERIT -18 /* inclusive */ #define OOM_ADJUST_MIN (-16) #define OOM_ADJUST_MAX 15 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fa4e1d79..d8340c73 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1230,6 +1230,7 @@ #define PCI_DEVICE_ID_INTERG_5050 0x5050 #define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8129 0x8129 #define PCI_DEVICE_ID_REALTEK_8139 0x8139 #define PCI_VENDOR_ID_XILINX 0x10ee @@ -2004,6 +2005,9 @@ #define PCI_VENDOR_ID_NETCELL 0x169c #define PCI_DEVICE_ID_REVOLUTION 0x0044 +#define PCI_VENDOR_ID_SAFENET 0x1148 +#define PCI_DEVICE_ID_SAFENET_1141 0x1141 + #define PCI_VENDOR_ID_VITESSE 0x1725 #define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h index e86a7a5c..f3552a44 100644 --- a/include/linux/ppp-comp.h +++ b/include/linux/ppp-comp.h @@ -193,6 +193,13 @@ struct compressor { #define DEFLATE_CHK_SEQUENCE 0 /* + * Definitions for Stac LZS. + */ + +#define CI_LZS 17 /* config option for Stac LZS */ +#define CILEN_LZS 5 /* length of config option */ + +/* * Definitions for MPPE. */ diff --git a/include/linux/serial.h b/include/linux/serial.h index 33fc8cb8..0475b13d 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -81,6 +81,7 @@ struct serial_struct { #define SERIAL_IO_PORT 0 #define SERIAL_IO_HUB6 1 #define SERIAL_IO_MEM 2 +#define SERIAL_IO_MEM32 3 struct serial_uart_config { char *name; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 463ab953..f6700b51 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -132,6 +132,26 @@ #define PORT_S3C2412 73 +/* Motorola ColdFire */ +#define PORT_MCF 74 + +/* DCC(JTAG) emulation port types */ +#define PORT_DCC_JTAG1 75 + +/* Samsung S3C4510B */ +#define PORT_S3C4510B 76 + +#define PORT_P2001 77 + +/* TI TMS320DM270 */ +#define PORT_DM270 78 + +/* KS8695 */ +#define PORT_KS8695 79 + +/* Alter Nios II UART */ +#define PORT_JTAG_UART 80 + #ifdef __KERNEL__ diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h index 3c8a6aa7..3cc9b0c1 100644 --- a/include/linux/serial_reg.h +++ b/include/linux/serial_reg.h @@ -169,7 +169,15 @@ * In: Fifo count * Out: Fifo custom trigger levels */ /* - * These are the definitions for the Programmable Trigger Register + * The Intel XScale UARTS define these + */ +#define UART_IER_DMAE 0x80 /* DMA Requests Enable */ +#define UART_IER_UUE 0x40 /* UART Unit Enable */ +#define UART_IER_NRZE 0x20 /* NRZ coding Enable */ +#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ + +/* + * These are the definitions for the Modem Control Register */ #define UART_TRG_1 0x01 #define UART_TRG_4 0x04 diff --git a/include/linux/squashfs_fs.h b/include/linux/squashfs_fs.h new file mode 100644 index 00000000..7a63e6e8 --- /dev/null +++ b/include/linux/squashfs_fs.h @@ -0,0 +1,523 @@ +#ifndef SQUASHFS_FS +#define SQUASHFS_FS +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005 Phillip Lougher + * + * 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, + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs.h + */ + +#ifdef CONFIG_SQUASHFS_VMALLOC +#define SQUASHFS_ALLOC(a) vmalloc(a) +#define SQUASHFS_FREE(a) vfree(a) +#else +#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL) +#define SQUASHFS_FREE(a) kfree(a) +#endif +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE +#define SQUASHFS_MAJOR 2 +#define SQUASHFS_MINOR 1 +#define SQUASHFS_MAGIC 0x73717368 +#define SQUASHFS_MAGIC_SWAP 0x68737173 +#define SQUASHFS_START 0 + +/* size of metadata (inode and directory) blocks */ +#define SQUASHFS_METADATA_SIZE 8192 +#define SQUASHFS_METADATA_LOG 13 + +/* default size of data blocks */ +#define SQUASHFS_FILE_SIZE 65536 +#define SQUASHFS_FILE_LOG 16 + +#define SQUASHFS_FILE_MAX_SIZE 65536 + +/* Max number of uids and gids */ +#define SQUASHFS_UIDS 256 +#define SQUASHFS_GUIDS 255 + +/* Max length of filename (not 255) */ +#define SQUASHFS_NAME_LEN 256 + +#define SQUASHFS_INVALID ((long long) 0xffffffffffff) +#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff) +#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) + +/* Filesystem flags */ +#define SQUASHFS_NOI 0 +#define SQUASHFS_NOD 1 +#define SQUASHFS_CHECK 2 +#define SQUASHFS_NOF 3 +#define SQUASHFS_NO_FRAG 4 +#define SQUASHFS_ALWAYS_FRAG 5 +#define SQUASHFS_DUPLICATE 6 +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI) +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD) +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF) +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG) +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG) +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE) +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK) +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6)) + +/* Max number of types and file types */ +#define SQUASHFS_DIR_TYPE 1 +#define SQUASHFS_FILE_TYPE 2 +#define SQUASHFS_SYMLINK_TYPE 3 +#define SQUASHFS_BLKDEV_TYPE 4 +#define SQUASHFS_CHRDEV_TYPE 5 +#define SQUASHFS_FIFO_TYPE 6 +#define SQUASHFS_SOCKET_TYPE 7 +#define SQUASHFS_LDIR_TYPE 8 + +/* 1.0 filesystem type definitions */ +#define SQUASHFS_TYPES 5 +#define SQUASHFS_IPC_TYPE 0 + +/* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */ +#define SQUASHFS_COMPRESSED_BIT (1 << 15) +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) + +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) + +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \ + (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) + +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) + +/* + * Inode number ops. Inodes consist of a compressed block number, and an uncompressed + * offset within that block + */ +#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) +#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\ + + (B))) + +/* Compute 32 bit VFS inode number from squashfs inode number */ +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1)) + +/* Translate between VFS mode and squashfs mode */ +#define SQUASHFS_MODE(a) ((a) & 0xfff) + +/* fragment and fragment table defines */ +typedef unsigned int squashfs_fragment_index; +#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry)) +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE) +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE) +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE) +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index)) + +/* cached data constants for filesystem */ +#define SQUASHFS_CACHED_BLKS 8 + +#define SQUASHFS_MAX_FILE_SIZE_LOG 32 +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) + +#define SQUASHFS_MARKER_BYTE 0xff + + +/* + * definitions for structures on disk + */ + +typedef unsigned int squashfs_block; +typedef long long squashfs_inode; + +typedef unsigned int squashfs_uid; + +typedef struct squashfs_super_block { +#ifdef CONFIG_SQUASHFS_CRAMFS_MAGIC + unsigned char cramfs_magic[4]; + unsigned char cramfs_size[4]; +#endif + unsigned int s_magic; + unsigned int inodes; + unsigned int bytes_used; + unsigned int uid_start; + unsigned int guid_start; + unsigned int inode_table_start; + unsigned int directory_table_start; + unsigned int s_major:16; + unsigned int s_minor:16; + unsigned int block_size_1:16; + unsigned int block_log:16; + unsigned int flags:8; + unsigned int no_uids:8; + unsigned int no_guids:8; + unsigned int mkfs_time /* time of filesystem creation */; + squashfs_inode root_inode; + unsigned int block_size; + unsigned int fragments; + unsigned int fragment_table_start; +} __attribute__ ((packed)) squashfs_super_block; + +typedef struct { + unsigned int index:27; + unsigned int start_block:29; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)) squashfs_dir_index; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)) squashfs_base_inode_header; + +typedef squashfs_base_inode_header squashfs_ipc_inode_header; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)) squashfs_dev_inode_header; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)) squashfs_symlink_inode_header; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int mtime; + squashfs_block start_block; + unsigned int fragment; + unsigned int offset; + unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned short block_list[0]; +} __attribute__ ((packed)) squashfs_reg_inode_header; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)) squashfs_dir_inode_header; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:27; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; + unsigned int i_count:16; + squashfs_dir_index index[0]; +} __attribute__ ((packed)) squashfs_ldir_inode_header; + +typedef union { + squashfs_base_inode_header base; + squashfs_dev_inode_header dev; + squashfs_symlink_inode_header symlink; + squashfs_reg_inode_header reg; + squashfs_dir_inode_header dir; + squashfs_ldir_inode_header ldir; + squashfs_ipc_inode_header ipc; +} squashfs_inode_header; + +typedef struct { + unsigned int offset:13; + unsigned int type:3; + unsigned int size:8; + char name[0]; +} __attribute__ ((packed)) squashfs_dir_entry; + +typedef struct { + unsigned int count:8; + unsigned int start_block:24; +} __attribute__ ((packed)) squashfs_dir_header; + +typedef struct { + unsigned int start_block; + unsigned int size; +} __attribute__ ((packed)) squashfs_fragment_entry; + +extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); +extern int squashfs_uncompress_init(void); +extern int squashfs_uncompress_exit(void); + +/* + * macros to convert each packed bitfield structure from little endian to big + * endian and vice versa. These are needed when creating or using a filesystem on a + * machine with different byte ordering to the target architecture. + * + */ + +#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ + SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ + SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ + SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ + SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ + SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ + SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ + SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ + SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\ + SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ + SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ + SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ + SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ + SQUASHFS_SWAP((s)->flags, d, 288, 8);\ + SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ + SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ + SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ + SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ + SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ + SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ + SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\ +} + +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) + +#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ + SQUASHFS_SWAP((s)->offset, d, 128, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ + SQUASHFS_SWAP((s)->offset, d, 51, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ldir_inode_header));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ + SQUASHFS_SWAP((s)->offset, d, 59, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ + SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_index));\ + SQUASHFS_SWAP((s)->index, d, 0, 27);\ + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ + SQUASHFS_SWAP((s)->size, d, 56, 8);\ +} + +#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ + SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ + SQUASHFS_SWAP((s)->count, d, 0, 8);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ +} + +#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ + SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ + SQUASHFS_SWAP((s)->type, d, 13, 3);\ + SQUASHFS_SWAP((s)->size, d, 16, 8);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ + SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ + SQUASHFS_SWAP((s)->size, d, 32, 32);\ +} + +#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_MEMSET(s, d, n * 2);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ +} + +#define SQUASHFS_SWAP_INTS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_MEMSET(s, d, n * 4);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ +} + +#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ + int entry;\ + int bit_position;\ + SQUASHFS_MEMSET(s, d, n * bits / 8);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\ + SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) + +#ifdef SQUASHFS_1_0_COMPATIBILITY +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ +} __attribute__ ((packed)) squashfs_base_inode_header_1; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int type:4; + unsigned int offset:4; +} __attribute__ ((packed)) squashfs_ipc_inode_header_1; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)) squashfs_dev_inode_header_1; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)) squashfs_symlink_inode_header_1; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int mtime; + squashfs_block start_block; + unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned short block_list[0]; +} __attribute__ ((packed)) squashfs_reg_inode_header_1; + +typedef struct { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)) squashfs_dir_inode_header_1; + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 4);\ + SQUASHFS_SWAP((s)->guid, d, 20, 4);\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\ + SQUASHFS_SWAP((s)->type, d, 24, 4);\ + SQUASHFS_SWAP((s)->offset, d, 28, 4);\ +} + +#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ + SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ + SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\ + SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\ + SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ + SQUASHFS_SWAP((s)->offset, d, 43, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ +} +#endif + +#ifdef __KERNEL__ +/* + * macros used to swap each structure entry, taking into account + * bitfields and different bitfield placing conventions on differing architectures + */ +#include +#ifdef __BIG_ENDIAN + /* convert from little endian to big endian */ +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) +#else + /* convert from big endian to little endian */ +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) +#endif + +#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ + int bits;\ + int b_pos = pos % 8;\ + unsigned long long val = 0;\ + unsigned char *s = (unsigned char *)p + (pos / 8);\ + unsigned char *d = ((unsigned char *) &val) + 7;\ + for(bits = 0; bits < (tbits + b_pos); bits += 8) \ + *d-- = *s++;\ + value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ +} +#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); +#endif +#endif diff --git a/include/linux/squashfs_fs_i.h b/include/linux/squashfs_fs_i.h new file mode 100644 index 00000000..0d6a8795 --- /dev/null +++ b/include/linux/squashfs_fs_i.h @@ -0,0 +1,43 @@ +#ifndef SQUASHFS_FS_I +#define SQUASHFS_FS_I +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005 Phillip Lougher + * + * 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, + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs_i.h + */ + +typedef struct squashfs_inode_info { + unsigned int start_block; + unsigned int block_list_start; + unsigned int offset; + union { + struct { + unsigned int fragment_start_block; + unsigned int fragment_size; + unsigned int fragment_offset; + } s1; + struct { + unsigned int directory_index_start; + unsigned int directory_index_offset; + unsigned int directory_index_count; + } s2; + } u; + struct inode vfs_inode; + } squashfs_inode_info; +#endif diff --git a/include/linux/squashfs_fs_sb.h b/include/linux/squashfs_fs_sb.h new file mode 100644 index 00000000..615a8cee --- /dev/null +++ b/include/linux/squashfs_fs_sb.h @@ -0,0 +1,65 @@ +#ifndef SQUASHFS_FS_SB +#define SQUASHFS_FS_SB +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005 Phillip Lougher + * + * 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, + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs_sb.h + */ + +#include + +typedef struct { + unsigned int block; + int length; + unsigned int next_index; + char *data; + } squashfs_cache; + +struct squashfs_fragment_cache { + unsigned int block; + int length; + unsigned int locked; + char *data; + }; + +typedef struct squashfs_sb_info { + squashfs_super_block sBlk; + int devblksize; + int devblksize_log2; + int swap; + squashfs_cache *block_cache; + struct squashfs_fragment_cache *fragment; + int next_cache; + int next_fragment; + squashfs_uid *uid; + squashfs_uid *guid; + squashfs_fragment_index *fragment_index; + unsigned int read_size; + char *read_data; + char *read_page; + struct semaphore read_page_mutex; + struct semaphore block_cache_mutex; + struct semaphore fragment_mutex; + wait_queue_head_t waitq; + wait_queue_head_t fragment_wait_queue; + struct inode *(*iget)(struct super_block *s, squashfs_inode inode); + unsigned int (*read_blocklist)(struct inode *inode, int index, int readahead_blks, + char *block_list, unsigned short **block_p, unsigned int *bsize); + } squashfs_sb_info; +#endif diff --git a/include/linux/string.h b/include/linux/string.h index 4f69ef9e..6dbcdfd7 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -80,11 +80,15 @@ extern __kernel_size_t strcspn(const char *,const char *); #endif #ifndef __HAVE_ARCH_MEMSET +#if 0 // mask by Victor Yu. 02-12-2007 extern void * memset(void *,int,__kernel_size_t); #endif +#endif #ifndef __HAVE_ARCH_MEMCPY +#if 0 // mask by Victor Yu. 02-12-2007 extern void * memcpy(void *,const void *,__kernel_size_t); #endif +#endif #ifndef __HAVE_ARCH_MEMMOVE extern void * memmove(void *,const void *,__kernel_size_t); #endif @@ -92,8 +96,10 @@ extern void * memmove(void *,const void *,__kernel_size_t); extern void * memscan(void *,int,__kernel_size_t); #endif #ifndef __HAVE_ARCH_MEMCMP +#if 0 // mask by Victor Yu. 02-12-2007 extern int memcmp(const void *,const void *,__kernel_size_t); #endif +#endif #ifndef __HAVE_ARCH_MEMCHR extern void * memchr(const void *,int,__kernel_size_t); #endif diff --git a/include/linux/types.h b/include/linux/types.h index 750f085f..7ce9c530 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -33,7 +33,9 @@ typedef __kernel_clockid_t clockid_t; typedef __kernel_mqd_t mqd_t; #ifdef __KERNEL__ +#if 0 // msk by Victor Yu. 02-12-2007 typedef _Bool bool; +#endif typedef __kernel_uid32_t uid_t; typedef __kernel_gid32_t gid_t; diff --git a/include/linux/usb_isp1362.h b/include/linux/usb_isp1362.h new file mode 100644 index 00000000..381c3afc --- /dev/null +++ b/include/linux/usb_isp1362.h @@ -0,0 +1,42 @@ + +/* + * board initialization code should put one of these into dev->platform_data + * and place the isp1362 onto platform_bus. + */ + +struct isp1362_platform_data { + // Enable internal pulldown resistors on downstream ports + unsigned sel15Kres:1; + // Clock cannot be stopped + unsigned clknotstop:1; + // On-chip overcurrent protection + unsigned oc_enable:1; + // INT output polarity + unsigned int_act_high:1; + // INT edge or level triggered + unsigned int_edge_triggered:1; + // DREQ output polarity + unsigned dreq_act_high:1; + // DACK input polarity + unsigned dack_act_high:1; + // chip can be resumed via H_WAKEUP pin + unsigned remote_wakeup_connected:1; + // Switch or not to switch (keep always powered) + unsigned no_power_switching:1; + // Ganged port power switching (0) or individual port power switching (1) + unsigned power_switching_mode:1; + // Given port_power, msec/2 after power on till power good + u8 potpg; + // Hardware reset set/clear + void (*reset) (struct device *dev, int set); + // Clock start/stop + void (*clock) (struct device *dev, int start); + /* Inter-io delay (ns). The chip is picky about access timings; it + expects at least: + 110ns delay between consecutive accesses to DATA_REG, + 300ns delay between access to ADDR_REG and DATA_REG (registers) + 462ns delay between access to ADDR_REG and DATA_REG (buffer memory) + WE MUST NOT be activated during these intervals (even without CS!) + */ + void (*delay) (struct device *dev, unsigned int delay); +}; diff --git a/include/net/xfrmudp.h b/include/net/xfrmudp.h new file mode 100644 index 00000000..d0da2297 --- /dev/null +++ b/include/net/xfrmudp.h @@ -0,0 +1,10 @@ +/* + * pointer to function for type that xfrm4_input wants, to permit + * decoupling of XFRM from udp.c + */ +#define HAVE_XFRM4_UDP_REGISTER + +typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type); +extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func + , xfrm4_rcv_encap_t *oldfunc); +extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func); diff --git a/init/Kconfig b/init/Kconfig index 176f7e51..2a755297 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -445,7 +445,7 @@ config RT_MUTEXES config TINY_SHMEM default !SHMEM - bool + bool "Support tiny share memory" config BASE_SMALL int diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index ed652f40..e9ed4884 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, int out_fd); * numbers could not be found. * * We currently check for the following magic numbers: + * squashfs * minix * ext2 * romfs @@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start_block) struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; struct cramfs_super *cramfsb; + struct squashfs_super_block *squashfsb; int nblocks = -1; unsigned char *buf; @@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start_block) ext2sb = (struct ext2_super_block *) buf; romfsb = (struct romfs_super_block *) buf; cramfsb = (struct cramfs_super *) buf; + squashfsb = (struct squashfs_super_block *) buf; memset(buf, 0xe5, size); /* @@ -93,11 +97,20 @@ identify_ramdisk_image(int fd, int start_block) goto done; } - if (cramfsb->magic == CRAMFS_MAGIC) { + if (cramfsb->magic == le32_to_cpu(CRAMFS_MAGIC)) { printk(KERN_NOTICE "RAMDISK: cramfs filesystem found at block %d\n", start_block); - nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; + nblocks = (le32_to_cpu(cramfsb->size) + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; + goto done; + } + + /* squashfs is at block zero too */ + if (squashfsb->s_magic == SQUASHFS_MAGIC) { + printk(KERN_NOTICE + "RAMDISK: squashfs filesystem found at block %d\n", + start_block); + nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; goto done; } diff --git a/init/main.c b/init/main.c index 36f608a7..befe435d 100644 --- a/init/main.c +++ b/init/main.c @@ -70,7 +70,7 @@ * too old from the very beginning. */ #if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2) -#error Sorry, your GCC is too old. It builds incorrect kernels. +#warning Sorry, your GCC is too old. It may build incorrect kernels. #endif static int init(void *); @@ -399,6 +399,7 @@ static void __init smp_init(void) #endif +#define VICTOR_UART(x) {*(volatile unsigned int *)0x98200000 = (x);} /* * We need to finalize in a non-__init function or else race conditions * between the root thread and the init thread may cause start_kernel to @@ -407,7 +408,6 @@ static void __init smp_init(void) * * gcc-3.4 accidentally inlines this function, so use noinline. */ - static void noinline rest_init(void) __releases(kernel_lock) { @@ -505,6 +505,25 @@ asmlinkage void __init start_kernel(void) setup_arch(&command_line); unwind_setup(); setup_per_cpu_areas(); +#if 1 // add by Victor Yu. for debug using 07-27-2007, Fraddy tell me this issue + { + int tlb, entry, way, rd, index; + rd = 0xF9400003; // garbage address for lock + for ( tlb=0; tlb<2; tlb++ ) { + for (way=0; way<4; way++ ) { + for (entry=0; entry<16; entry++ ) { + index = ((tlb << 24) | (way << 22) | (entry << 18)) & 0x1FC0000; + asm("mcr p15, 4, %0, c15, c0, 1" + : + : "r" (index)); + asm("mcr p15, 4, %0, c15, c6, 0" + : + : "r" (rd)); + } + } + } + } +#endif smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ /* diff --git a/ipc/msg.c b/ipc/msg.c index 1266b1d0..79783014 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -606,12 +606,14 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) msr->r_msgtype, msr->r_mode)) { list_del(&msr->r_list); +#if 0 // mask by Victor Yu. 03-02-2007 if (msr->r_maxsize < msg->m_ts) { msr->r_msg = NULL; wake_up_process(msr->r_tsk); smp_mb(); msr->r_msg = ERR_PTR(-E2BIG); } else { +#endif msr->r_msg = NULL; msq->q_lrpid = msr->r_tsk->pid; msq->q_rtime = get_seconds(); @@ -620,7 +622,9 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) msr->r_msg = msg; return 1; +#if 0 // mask by Victor Yu. 03-02-2007 } +#endif } } return 0; diff --git a/kernel/compat.c b/kernel/compat.c index 6952dd05..3ae8514b 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -856,6 +856,7 @@ asmlinkage long compat_sys_time(compat_time_t __user * tloc) return i; } +#error ICSA specification requires the logging of time changes. This architecture will not log changes via compat_sys_stime. asmlinkage long compat_sys_stime(compat_time_t __user *tptr) { struct timespec tv; diff --git a/kernel/fork.c b/kernel/fork.c index 8cdd3e72..2adf02ff 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -1158,6 +1159,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->pdeath_signal = 0; p->exit_state = 0; + if (p->oomkilladj == OOM_DISABLE_NOINHERIT) + p->oomkilladj = 0; + /* * Ok, make it visible to the rest of the system. * We dont wake it up yet. diff --git a/kernel/printk.c b/kernel/printk.c index 66426552..e4a0accb 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1112,8 +1112,13 @@ EXPORT_SYMBOL(printk_ratelimit); * milliseconds have elapsed since the last time printk_timed_ratelimit() * returned true. */ +#if 0 // mask by Victor Yu. 02-12-2007 bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msecs) +#else +int printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msecs) +#endif { if (*caller_jiffies == 0 || time_after(jiffies, *caller_jiffies)) { *caller_jiffies = jiffies + msecs_to_jiffies(interval_msecs); diff --git a/kernel/softirq.c b/kernel/softirq.c index bf25015d..e684f4f8 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -61,6 +61,13 @@ static inline void wakeup_softirqd(void) wake_up_process(tsk); } +static inline int softirqd_is_waken(void) +{ + struct task_struct *tsk = __get_cpu_var(ksoftirqd); + + return tsk && tsk->state == TASK_RUNNING; +} + /* * This one is for softirq.c-internal use, * where hardirqs are disabled legitimately: @@ -203,7 +210,7 @@ EXPORT_SYMBOL(local_bh_enable_ip); */ #define MAX_SOFTIRQ_RESTART 10 -asmlinkage void __do_softirq(void) +static asmlinkage void __do_softirq2(void) { struct softirq_action *h; __u32 pending; @@ -249,6 +256,12 @@ restart: _local_bh_enable(); } +asmlinkage void __do_softirq(void) +{ + if (!softirqd_is_waken()) + __do_softirq2(); +} + #ifndef __ARCH_HAS_DO_SOFTIRQ asmlinkage void do_softirq(void) @@ -469,6 +482,8 @@ void __init softirq_init(void) static int ksoftirqd(void * __bind_cpu) { + unsigned long flags; + set_user_nice(current, 19); current->flags |= PF_NOFREEZE; @@ -490,7 +505,11 @@ static int ksoftirqd(void * __bind_cpu) don't process */ if (cpu_is_offline((long)__bind_cpu)) goto wait_to_die; - do_softirq(); + + local_irq_save(flags); + __do_softirq2(); + local_irq_restore(flags); + preempt_enable_no_resched(); cond_resched(); preempt_disable(); diff --git a/kernel/time.c b/kernel/time.c index 0e017bff..9c9f0d0e 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -48,6 +48,63 @@ struct timezone sys_tz; EXPORT_SYMBOL(sys_tz); +#ifndef __ARCH_WANT_SYS_TIME +#error ICSA specification requires the logging of time changes. This architecture will not log changes. +#endif + +static void print_time_change(const char *msg, struct timeval new_tv) +{ + long s, j, d, m, y; + + j = new_tv.tv_sec / 86400L + 719469; + s = new_tv.tv_sec % 86400L; + + if( s < 0 ) { s += 86400L; j--; } + + y = (4L * j - 1L) / 146097L; + j = 4L * j - 1L - 146097L * y; + d = j / 4L; + j = (4L * d + 3L) / 1461L; + d = 4L * d + 3L - 1461L * j; + d = (d + 4L) / 4L; + m = (5L * d - 3L) / 153L; + d = 5L * d - 3 - 153L * m; + d = (d + 5L) / 5L; + y = 100L * y + j; + if (m < 10) + m += 2; + else + { + m -= 10; + ++y; + } + printk(KERN_NOTICE "Clock: %s time %04d/%02d/%02d - %02d:%02d:%02d GMT\n", + msg, (int) y, (int) m + 1, (int) d, (int) (s / 3600 ), (int) (s / 60) % 60, (int) s % 60); +} + +#ifndef ABS +#define ABS(X) ((X) < 0 ? -(X) : (X)) +#endif + +static void check_print_time_change(const struct timeval old_tv, const struct timeval new_tv) +{ + static long accumulated_usecs; + + if (ABS(new_tv.tv_sec - old_tv.tv_sec) <= 2) { + /* No more than 2 seconds of change */ + accumulated_usecs += (new_tv.tv_sec - old_tv.tv_sec) * 1000000L + (new_tv.tv_usec - old_tv.tv_usec); + if (ABS(accumulated_usecs) < 1000000L) { + /* Less than 1 second of accumulated change */ + return; + } + } + + accumulated_usecs = 0; + + print_time_change("old", old_tv); + print_time_change("new", new_tv); +} + #ifdef __ARCH_WANT_SYS_TIME /* @@ -82,6 +139,7 @@ asmlinkage long sys_stime(time_t __user *tptr) { struct timespec tv; int err; + struct timeval old_tv, new_tv; if (get_user(tv.tv_sec, tptr)) return -EFAULT; @@ -92,7 +150,10 @@ asmlinkage long sys_stime(time_t __user *tptr) if (err) return err; + do_gettimeofday(&old_tv); do_settimeofday(&tv); + do_gettimeofday(&new_tv); + check_print_time_change(old_tv, new_tv); return 0; } @@ -154,6 +215,7 @@ int do_sys_settimeofday(struct timespec *tv, struct timezone *tz) { static int firsttime = 1; int error = 0; + struct timeval old_tv, new_tv; if (tv && !timespec_valid(tv)) return -EINVAL; @@ -176,9 +238,12 @@ int do_sys_settimeofday(struct timespec *tv, struct timezone *tz) /* SMP safe, again the code in arch/foo/time.c should * globally block out interrupts when it runs. */ - return do_settimeofday(tv); + do_gettimeofday(&old_tv); + error = do_settimeofday(tv); + do_gettimeofday(&new_tv); + check_print_time_change(old_tv, new_tv); } - return 0; + return error; } asmlinkage long sys_settimeofday(struct timeval __user *tv, diff --git a/kernel/timer.c b/kernel/timer.c index c1c7fbcf..a66cdba1 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1066,6 +1066,9 @@ static inline void update_times(unsigned long ticks) void do_timer(unsigned long ticks) { jiffies_64 += ticks; +#ifdef CONFIG_SNAPDOG + snapdog_service(); +#endif update_times(ticks); } diff --git a/linux.bin b/linux.bin new file mode 100755 index 0000000000000000000000000000000000000000..33019c93592efaeb489782a71acbf0ea852ed89b GIT binary patch literal 2005800 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:gHx2B2tWJjOzEzS?K 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 z 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 z

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

38Uo40_Tw?j<=JHYE9 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%0DtPYbVyubhG3 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%0Al0`pV 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 tB+meVwYthPhOm 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π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�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 z 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

0UY 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 MwiNDAXy literal 0 HcwPel00001 diff --git a/mm/filemap.c b/mm/filemap.c index 7b84dc81..283fdc8c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -40,9 +40,18 @@ #include +#ifdef CONFIG_DIRECTIO static ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs); +#else +static inline ssize_t +generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + return -EINVAL; +} +#endif /* * Shared mappings implemented 30.11.1994. It's not fully working yet, @@ -114,17 +123,29 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, */ void __remove_from_page_cache(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif radix_tree_delete(&mapping->page_tree, page->index); +#if 0 // mask by Victor Yu. 02-12-2007 page->mapping = NULL; +#else + page->u.xx.mapping = NULL; +#endif mapping->nrpages--; __dec_zone_page_state(page, NR_FILE_PAGES); } void remove_from_page_cache(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif BUG_ON(!PageLocked(page)); @@ -445,7 +466,11 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, if (!error) { page_cache_get(page); SetPageLocked(page); +#if 0 // mask by Victor Yu. 02-12-2007 page->mapping = mapping; +#else + page->u.xx.mapping = mapping; +#endif page->index = offset; mapping->nrpages++; __inc_zone_page_state(page, NR_FILE_PAGES); @@ -651,8 +676,13 @@ repeat: read_lock_irq(&mapping->tree_lock); /* Has the page been truncated while we slept? */ +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(page->mapping != mapping || page->index != offset)) { +#else + if (unlikely(page->u.xx.mapping != mapping || + page->index != offset)) { +#endif unlock_page(page); page_cache_release(page); goto repeat; @@ -761,7 +791,11 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, ret = radix_tree_gang_lookup(&mapping->page_tree, (void **)pages, index, nr_pages); for (i = 0; i < ret; i++) { +#if 0 // mask by Victor Yu. 02-12-2007 if (pages[i]->mapping == NULL || pages[i]->index != index) +#else + if (pages[i]->u.xx.mapping == NULL || pages[i]->index != index) +#endif break; page_cache_get(pages[i]); @@ -976,7 +1010,11 @@ page_not_up_to_date: lock_page(page); /* Did it get truncated before we got the lock? */ +#if 0 // mask by Victor Yu. 02-12-2007 if (!page->mapping) { +#else + if (!page->u.xx.mapping) { +#endif unlock_page(page); page_cache_release(page); continue; @@ -1003,7 +1041,11 @@ readpage: if (!PageUptodate(page)) { lock_page(page); if (!PageUptodate(page)) { +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping == NULL) { +#else + if (page->u.xx.mapping == NULL) { +#endif /* * invalidate_inode_pages got it */ @@ -1813,7 +1855,11 @@ retry: goto out; lock_page(page); +#if 0 // mask by Victor Yu. 02-12-2007 if (!page->mapping) { +#else + if (!page->u.xx.mapping) { +#endif unlock_page(page); page_cache_release(page); goto retry; @@ -2385,6 +2431,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, } EXPORT_SYMBOL(generic_file_aio_write); +#ifdef CONFIG_DIRECTIO /* * Called under i_mutex for writes to S_ISREG files. Returns -EIO if something * went wrong during pagecache shootdown. @@ -2424,6 +2471,7 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } return retval; } +#endif /** * try_to_release_page() - release old fs-specific metadata on a page @@ -2442,7 +2490,11 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, */ int try_to_release_page(struct page *page, gfp_t gfp_mask) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space * const mapping = page->mapping; +#else + struct address_space * const mapping = page->u.xx.mapping; +#endif BUG_ON(!PageLocked(page)); if (PageWriteback(page)) diff --git a/mm/nommu.c b/mm/nommu.c index 8bdde950..03e205b0 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -32,6 +32,14 @@ #include #include +//#define VICTOR_DEBUG 1 + +#ifdef VICTOR_DEBUG +#define victor_debug(x...) printk(x) +#else +#define victor_debug(x...) +#endif // VICTOR_DEBUG + void *high_memory; struct page *mem_map; unsigned long max_mapnr; @@ -45,6 +53,9 @@ int heap_stack_gap = 0; EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(__vm_enough_memory); +#if 1 // add by Victor Yu. 04-10-2007, it needs by iptables +EXPORT_SYMBOL(num_physpages); +#endif /* list of shareable VMAs */ struct rb_root nommu_vma_tree = RB_ROOT; @@ -493,28 +504,46 @@ static int validate_mmap_request(struct file *file, return -EINVAL; } +#if 0 // add by Victor Yu. 01-07-2008 + if ( (flags & MAP_TYPE) == MAP_SHARED ) { + flags &= ~MAP_TYPE; + flags |= MAP_PRIVATE; + } +#endif + if ((flags & MAP_TYPE) != MAP_PRIVATE && - (flags & MAP_TYPE) != MAP_SHARED) + (flags & MAP_TYPE) != MAP_SHARED) { return -EINVAL; + } - if (PAGE_ALIGN(len) == 0) - return addr; - - if (len > TASK_SIZE) + if (!len) { return -EINVAL; + } + + /* Careful about overflows.. */ + len = PAGE_ALIGN(len); + if (!len || len > TASK_SIZE) { + return -ENOMEM; + } /* offset overflow? */ - if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) - return -EINVAL; + if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) { + return -EOVERFLOW; + } if (file) { /* validate file mapping requests */ struct address_space *mapping; /* files must support mmap */ - if (!file->f_op || !file->f_op->mmap) + if (!file->f_op || !file->f_op->mmap) { return -ENODEV; + } +#if 0 // add by Victor Yu. 02-15-2007, I changed the insmod application. + flags |= MAP_PRIVATE; + flags &= !MAP_SHARED; +#endif /* work out if what we've got could possibly be shared * - we support chardevs that provide their own "memory" * - we support files/blockdevs that are memory backed @@ -558,18 +587,22 @@ static int validate_mmap_request(struct file *file, if (flags & MAP_SHARED) { /* do checks for writing, appending and locking */ if ((prot & PROT_WRITE) && - !(file->f_mode & FMODE_WRITE)) + !(file->f_mode & FMODE_WRITE)) { return -EACCES; + } if (IS_APPEND(file->f_dentry->d_inode) && - (file->f_mode & FMODE_WRITE)) + (file->f_mode & FMODE_WRITE)) { return -EACCES; + } - if (locks_verify_locked(file->f_dentry->d_inode)) + if (locks_verify_locked(file->f_dentry->d_inode)) { return -EAGAIN; + } - if (!(capabilities & BDI_CAP_MAP_DIRECT)) + if (!(capabilities & BDI_CAP_MAP_DIRECT)) { return -ENODEV; + } if (((prot & PROT_READ) && !(capabilities & BDI_CAP_READ_MAP)) || ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) || @@ -585,8 +618,9 @@ static int validate_mmap_request(struct file *file, else { /* we're going to read the file into private memory we * allocate */ - if (!(capabilities & BDI_CAP_MAP_COPY)) + if (!(capabilities & BDI_CAP_MAP_COPY)) { return -ENODEV; + } /* we don't permit a private writable mapping to be * shared with the backing device */ @@ -597,8 +631,9 @@ static int validate_mmap_request(struct file *file, /* handle executable mappings and implied executable * mappings */ if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) { - if (prot & PROT_EXEC) + if (prot & PROT_EXEC) { return -EPERM; + } } else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) { /* handle implication of PROT_EXEC by PROT_READ */ @@ -629,8 +664,9 @@ static int validate_mmap_request(struct file *file, /* allow the security API to have its say */ ret = security_file_mmap(file, reqprot, prot, flags); - if (ret < 0) + if (ret < 0) { return ret; + } /* looks okay */ *_capabilities = capabilities; @@ -652,6 +688,13 @@ static unsigned long determine_vm_flags(struct file *file, vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; /* vm_flags |= mm->def_flags; */ +#if 0 // add by Victor Yu. 01-07-2008 + if ( (flags & MAP_TYPE) == MAP_SHARED ) { + flags &= ~MAP_TYPE; + flags |= MAP_PRIVATE; + } +#endif + if (!(capabilities & BDI_CAP_MAP_DIRECT)) { /* attempt to share read-only copies of mapped file chunks */ if (file && !(prot & PROT_WRITE)) @@ -725,10 +768,12 @@ static int do_mmap_private(struct vm_area_struct *vma, unsigned long len) * we're allocating is smaller than a page */ base = kmalloc(len, GFP_KERNEL|__GFP_COMP); - if (!base) + if (!base) { goto enomem; + } vma->vm_start = (unsigned long) base; +victor_debug("%s allocation memory = 0x%x!\n", __FUNCTION__, vma->vm_start); vma->vm_end = vma->vm_start + len; vma->vm_flags |= VM_MAPPED_COPY; @@ -751,8 +796,9 @@ static int do_mmap_private(struct vm_area_struct *vma, unsigned long len) ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos); set_fs(old_fs); - if (ret < 0) + if (ret < 0) { goto error_free; + } /* clear the last little bit */ if (ret < len) @@ -771,9 +817,11 @@ error_free: return ret; enomem: +#if 0 // mask by Victor Yu. 03-14-2007 printk("Allocation of length %lu from process %d failed\n", len, current->pid); show_free_areas(); +#endif return -ENOMEM; } @@ -794,12 +842,19 @@ unsigned long do_mmap_pgoff(struct file *file, void *result; int ret; +#if 0 // add by Victor Yu. 01-07-2008 + if ( (flags & MAP_TYPE) == MAP_SHARED ) { + flags &= ~MAP_TYPE; + flags |= MAP_PRIVATE; + } +#endif /* decide whether we should attempt the mapping, and if so what sort of * mapping */ ret = validate_mmap_request(file, addr, len, prot, flags, pgoff, &capabilities); - if (ret < 0) + if (ret < 0) { return ret; + } /* we've determined that we can make the mapping, now translate what we * now know into VMA flags */ @@ -903,7 +958,7 @@ unsigned long do_mmap_pgoff(struct file *file, vml->vma = vma; /* set up the mapping */ - if (file && vma->vm_flags & VM_SHARED) + if (file && (vma->vm_flags & VM_SHARED) ) ret = do_mmap_shared_file(vma, len); else ret = do_mmap_private(vma, len); @@ -995,6 +1050,7 @@ static void put_vma(struct vm_area_struct *vma) realalloc -= kobjsize((void *) vma->vm_start); askedalloc -= vma->vm_end - vma->vm_start; kfree((void *) vma->vm_start); +victor_debug("%s free memory = 0x%x!\n", __FUNCTION__, vma->vm_start); } realalloc -= kobjsize(vma); @@ -1024,16 +1080,23 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) #endif for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) { - if ((*parent)->vma->vm_start > addr) +#if 1 // mask by Victor Yu. 03-03-3007 + if ((*parent)->vma->vm_start > addr) { break; + } +#endif if ((*parent)->vma->vm_start == addr && ((len == 0) || ((*parent)->vma->vm_end == end))) goto found; } +#if 1 // mask by Victor Yu. 03-03-2007 printk("munmap of non-mmaped memory by process %d (%s): %p\n", current->pid, current->comm, (void *) addr); return -EINVAL; +#else + return 0; +#endif found: vml = *parent; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 2e3ce3a9..3e145e1d 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -246,7 +246,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) *ppoints = ULONG_MAX; } - if (p->oomkilladj == OOM_DISABLE) + if (p->oomkilladj == OOM_DISABLE || + p->oomkilladj == OOM_DISABLE_NOINHERIT) continue; points = badness(p, uptime.tv_sec); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 8d9b19f2..765e5b6a 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -629,7 +629,11 @@ retry: */ lock_page(page); +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(page->mapping != mapping)) { +#else + if (unlikely(page->u.xx.mapping != mapping)) { +#endif unlock_page(page); continue; } @@ -712,7 +716,11 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc) */ int write_one_page(struct page *page, int wait) { +#if 0 // mask by Victor Yu. 02-12-2007 struct address_space *mapping = page->mapping; +#else + struct address_space *mapping = page->u.xx.mapping; +#endif int ret = 0; struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index aa6fcc7c..180a5d35 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -188,6 +188,7 @@ static inline int bad_range(struct zone *zone, struct page *page) static void bad_page(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 printk(KERN_EMERG "Bad page state in process '%s'\n" KERN_EMERG "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n" KERN_EMERG "Trying to fix it up, but a reboot is needed\n" @@ -195,6 +196,15 @@ static void bad_page(struct page *page) current->comm, page, (int)(2*sizeof(unsigned long)), (unsigned long)page->flags, page->mapping, page_mapcount(page), page_count(page)); +#else + printk(KERN_EMERG "Bad page state in process '%s'\n" + KERN_EMERG "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n" + KERN_EMERG "Trying to fix it up, but a reboot is needed\n" + KERN_EMERG "Backtrace:\n", + current->comm, page, (int)(2*sizeof(unsigned long)), + (unsigned long)page->flags, page->u.xx.mapping, + page_mapcount(page), page_count(page)); +#endif dump_stack(); page->flags &= ~(1 << PG_lru | 1 << PG_private | @@ -208,7 +218,11 @@ static void bad_page(struct page *page) 1 << PG_buddy ); set_page_count(page, 0); reset_page_mapcount(page); +#if 0 // mask by Victor Yu. 02-12-2007 page->mapping = NULL; +#else + page->u.xx.mapping = NULL; +#endif add_taint(TAINT_BAD_PAGE); } @@ -427,6 +441,7 @@ static inline void __free_one_page(struct page *page, static inline int free_pages_check(struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(page_mapcount(page) | (page->mapping != NULL) | (page_count(page) != 0) | @@ -441,6 +456,22 @@ static inline int free_pages_check(struct page *page) 1 << PG_writeback | 1 << PG_reserved | 1 << PG_buddy )))) +#else + if (unlikely(page_mapcount(page) | + (page->u.xx.mapping != NULL) | + (page_count(page) != 0) | + (page->flags & ( + 1 << PG_lru | + 1 << PG_private | + 1 << PG_locked | + 1 << PG_active | + 1 << PG_reclaim | + 1 << PG_slab | + 1 << PG_swapcache | + 1 << PG_writeback | + 1 << PG_reserved | + 1 << PG_buddy )))) +#endif bad_page(page); if (PageDirty(page)) __ClearPageDirty(page); @@ -576,6 +607,7 @@ static inline void expand(struct zone *zone, struct page *page, */ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) { +#if 0 // mask by Victor Yu. 02-12-2007 if (unlikely(page_mapcount(page) | (page->mapping != NULL) | (page_count(page) != 0) | @@ -591,6 +623,23 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) 1 << PG_writeback | 1 << PG_reserved | 1 << PG_buddy )))) +#else + if (unlikely(page_mapcount(page) | + (page->u.xx.mapping != NULL) | + (page_count(page) != 0) | + (page->flags & ( + 1 << PG_lru | + 1 << PG_private | + 1 << PG_locked | + 1 << PG_active | + 1 << PG_dirty | + 1 << PG_reclaim | + 1 << PG_slab | + 1 << PG_swapcache | + 1 << PG_writeback | + 1 << PG_reserved | + 1 << PG_buddy )))) +#endif bad_page(page); /* @@ -782,7 +831,11 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) unsigned long flags; if (PageAnon(page)) +#if 0 // mask by Victor Yu. 02-12-2007 page->mapping = NULL; +#else + page->u.xx.mapping = NULL; +#endif if (free_pages_check(page)) return; @@ -1095,8 +1148,10 @@ rebalance: if (page) goto got_pg; +#if 1 // mask by Victor Yu. 03-15-2007, I don't know why it will let system dead. out_of_memory(zonelist, gfp_mask, order); goto restart; +#endif } /* @@ -1119,6 +1174,7 @@ rebalance: } nopage: +#if 0 // mask by Victor Yu. 03-14-2007 if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) { printk(KERN_WARNING "%s: page allocation failure." " order:%d, mode:0x%x\n", @@ -1126,7 +1182,9 @@ nopage: dump_stack(); show_mem(); } +#endif got_pg: + return page; } @@ -2829,6 +2887,13 @@ static void setup_per_zone_lowmem_reserve(void) calculate_totalreserve_pages(); } +#if 1 // add by Victor Yu. 02-08-2007 +static u64 victor_do_div(u64 n, u32 base) +{ + do_div(n, base); + return n; +} +#endif /** * setup_per_zone_pages_min - called when min_free_kbytes changes. * @@ -2848,12 +2913,17 @@ void setup_per_zone_pages_min(void) lowmem_pages += zone->present_pages; } + for_each_zone(zone) { u64 tmp; spin_lock_irqsave(&zone->lru_lock, flags); tmp = (u64)pages_min * zone->present_pages; +#if 0 // mask by Victor Yu. 02-08-2007 do_div(tmp, lowmem_pages); +#else + tmp = victor_do_div(tmp, lowmem_pages); +#endif if (is_highmem(zone)) { /* * __GFP_HIGH and PF_MEMALLOC allocations usually don't @@ -3071,12 +3141,24 @@ void *__init alloc_large_system_hash(const char *tablename, /* limit allocation size to 1/16 total memory by default */ if (max == 0) { max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4; +#if 0 // mask by Victor Yu. 03-16-2007 do_div(max, bucketsize); +#else + max = victor_do_div(max, bucketsize); +#endif } if (numentries > max) numentries = max; + /* + * we will allocate at least a page (even on low memory systems) + * so do a fixup here to ensure we utilise the space that will be + * allocated, this also prevents us reporting -ve orders + */ + if (bucketsize * numentries < PAGE_SIZE) + numentries = (PAGE_SIZE + bucketsize - 1) / bucketsize; + log2qty = long_log2(numentries); do { diff --git a/mm/slab.c b/mm/slab.c index 3c4a7e34..a4e9f5bc 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -904,7 +904,11 @@ static void next_reap_node(void) #else #define init_reap_node(cpu) do { } while (0) +#if 0 // mask by Victor Yu. 02-12-2007 #define next_reap_node(void) do { } while (0) +#else +#define next_reap_node() +#endif #endif /* @@ -1495,8 +1499,7 @@ void __init kmem_cache_init(void) */ spin_lock_init(&ptr->lock); - malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = - ptr; + malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = ptr; local_irq_enable(); } /* 5) Replace the bootstrap kmem_list3's */ @@ -2944,8 +2947,9 @@ retry: spin_lock(&l3->list_lock); /* See if we can refill from the shared array */ - if (l3->shared && transfer_objects(ac, l3->shared, batchcount)) + if (l3->shared && transfer_objects(ac, l3->shared, batchcount)) { goto alloc_done; + } while (batchcount > 0) { struct list_head *entry; @@ -2955,8 +2959,9 @@ retry: if (entry == &l3->slabs_partial) { l3->free_touched = 1; entry = l3->slabs_free.next; - if (entry == &l3->slabs_free) + if (entry == &l3->slabs_free) { goto must_grow; + } } slabp = list_entry(entry, struct slab, list); @@ -2991,11 +2996,13 @@ alloc_done: /* cache_grow can reenable interrupts, then ac could change. */ ac = cpu_cache_get(cachep); - if (!x && ac->avail == 0) /* no objects in sight? abort */ + if (!x && ac->avail == 0) { /* no objects in sight? abort */ return NULL; + } - if (!ac->avail) /* objects refilled by interrupt? */ + if (!ac->avail) { /* objects refilled by interrupt? */ goto retry; + } } ac->touched = 1; return ac->entry[--ac->avail]; @@ -3097,8 +3104,7 @@ static __always_inline void *__cache_alloc(struct kmem_cache *cachep, local_irq_save(save_flags); - if (unlikely(NUMA_BUILD && - current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) + if (unlikely(NUMA_BUILD && current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) objp = alternate_node_alloc(cachep, flags); if (!objp) @@ -3110,8 +3116,7 @@ static __always_inline void *__cache_alloc(struct kmem_cache *cachep, if (NUMA_BUILD && !objp) objp = __cache_alloc_node(cachep, flags, numa_node_id()); local_irq_restore(save_flags); - objp = cache_alloc_debugcheck_after(cachep, flags, objp, - caller); + objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller); prefetchw(objp); return objp; } @@ -3491,8 +3496,9 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, * functions. */ cachep = __find_general_cachep(size, flags); - if (unlikely(cachep == NULL)) + if (unlikely(cachep == NULL)) { return NULL; + } return __cache_alloc(cachep, flags, caller); } diff --git a/mm/swapfile.c b/mm/swapfile.c index a15def63..1775c460 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -32,7 +32,11 @@ #include #include +#if 0 // mask by Victor Yu. 03-15-2007 DEFINE_SPINLOCK(swap_lock); +#else +spinlock_t swap_lock=SPIN_LOCK_UNLOCKED; +#endif unsigned int nr_swapfiles; long total_swap_pages; static int swap_overflow; diff --git a/mm/truncate.c b/mm/truncate.c index e07b1e68..a6205f66 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -34,7 +34,11 @@ void do_invalidatepage(struct page *page, unsigned long offset) { void (*invalidatepage)(struct page *, unsigned long); +#if 0 // mask by Victor Yu. 02-12-2007 invalidatepage = page->mapping->a_ops->invalidatepage; +#else + invalidatepage = page->u.xx.mapping->a_ops->invalidatepage; +#endif #ifdef CONFIG_BLOCK if (!invalidatepage) invalidatepage = block_invalidatepage; @@ -63,7 +67,11 @@ static inline void truncate_partial_page(struct page *page, unsigned partial) static void truncate_complete_page(struct address_space *mapping, struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping != mapping) +#else + if (page->u.xx.mapping != mapping) +#endif return; if (PagePrivate(page)) @@ -89,7 +97,11 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) { int ret; +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping != mapping) +#else + if (page->u.xx.mapping != mapping) +#endif return 0; if (PagePrivate(page) && !try_to_release_page(page, 0)) @@ -298,7 +310,11 @@ EXPORT_SYMBOL(invalidate_inode_pages); static int invalidate_complete_page2(struct address_space *mapping, struct page *page) { +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping != mapping) +#else + if (page->u.xx.mapping != mapping) +#endif return 0; if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL)) @@ -351,7 +367,11 @@ int invalidate_inode_pages2_range(struct address_space *mapping, int was_dirty; lock_page(page); +#if 0 // mask by Victor Yu. 02-12-2007 if (page->mapping != mapping) { +#else + if (page->u.xx.mapping != mapping) { +#endif unlock_page(page); continue; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 518540a4..08361a25 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -422,7 +422,12 @@ int remove_mapping(struct address_space *mapping, struct page *page) goto cannot_free; if (PageSwapCache(page)) { +#if 0 // mask by Victor Yu. 03-15-2007 swp_entry_t swap = { .val = page_private(page) }; +#else + swp_entry_t swap; + swap.val = page_private(page); +#endif __delete_from_swap_cache(page); write_unlock_irq(&mapping->tree_lock); swap_free(swap); @@ -1020,6 +1025,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) struct reclaim_state *reclaim_state = current->reclaim_state; unsigned long lru_pages = 0; int i; +#if 0 // mask by Victor Yu. 03-14-2007 struct scan_control sc = { .gfp_mask = gfp_mask, .may_writepage = !laptop_mode, @@ -1027,6 +1033,14 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask) .may_swap = 1, .swappiness = vm_swappiness, }; +#else + struct scan_control sc; + sc.gfp_mask = gfp_mask; + sc.may_writepage = !laptop_mode; + sc.swap_cluster_max = SWAP_CLUSTER_MAX; + sc.may_swap = 1; + sc.swappiness = vm_swappiness; +#endif count_vm_event(ALLOCSTALL); @@ -1125,6 +1139,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) unsigned long total_scanned; unsigned long nr_reclaimed; struct reclaim_state *reclaim_state = current->reclaim_state; +#if 0 // mask by Victor Yu. 03-14-2007 struct scan_control sc = { .gfp_mask = GFP_KERNEL, .may_swap = 1, @@ -1136,6 +1151,14 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) * this zone was successfully refilled to free_pages == pages_high. */ int temp_priority[MAX_NR_ZONES]; +#else + int temp_priority[MAX_NR_ZONES]; + struct scan_control sc; + sc.gfp_mask = GFP_KERNEL; + sc.may_swap = 1; + sc.swap_cluster_max = SWAP_CLUSTER_MAX; + sc.swappiness = vm_swappiness; +#endif loop_again: total_scanned = 0; @@ -1416,6 +1439,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages) int pass; struct reclaim_state reclaim_state; struct zone *zone; +#if 0 // mask by Victor Yu. 03-14-2007 struct scan_control sc = { .gfp_mask = GFP_KERNEL, .may_swap = 0, @@ -1423,6 +1447,14 @@ unsigned long shrink_all_memory(unsigned long nr_pages) .may_writepage = 1, .swappiness = vm_swappiness, }; +#else + struct scan_control sc; + sc.gfp_mask = GFP_KERNEL; + sc.may_swap = 0; + sc.swap_cluster_max = nr_pages; + sc.may_writepage = 1; + sc.swappiness = vm_swappiness; +#endif current->reclaim_state = &reclaim_state; @@ -1610,6 +1642,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) struct reclaim_state reclaim_state; int priority; unsigned long nr_reclaimed = 0; +#if 0 // mask by Victor Yu. 03-14-2007 struct scan_control sc = { .may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE), .may_swap = !!(zone_reclaim_mode & RECLAIM_SWAP), @@ -1619,6 +1652,15 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) .swappiness = vm_swappiness, }; unsigned long slab_reclaimable; +#else + unsigned long slab_reclaimable; + struct scan_control sc; + sc.may_writepage = !!(zone_reclaim_mode & RECLAIM_WRITE); + sc.may_swap = !!(zone_reclaim_mode & RECLAIM_SWAP); + sc.swap_cluster_max = max_t(unsigned long, nr_pages, SWAP_CLUSTER_MAX); + sc.gfp_mask = gfp_mask; + sc.swappiness = vm_swappiness; +#endif disable_swap_token(); cond_resched(); diff --git a/net/Kconfig b/net/Kconfig index 67e39ad8..67d7584a 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -245,6 +245,7 @@ endmenu source "net/ax25/Kconfig" source "net/irda/Kconfig" source "net/bluetooth/Kconfig" +source "../openswan/linux/net/ipsec/Kconfig" source "net/ieee80211/Kconfig" config WIRELESS_EXT diff --git a/net/Makefile b/net/Makefile index ad4d14f4..d606be27 100644 --- a/net/Makefile +++ b/net/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_ECONET) += econet/ obj-$(CONFIG_VLAN_8021Q) += 8021q/ obj-$(CONFIG_IP_DCCP) += dccp/ obj-$(CONFIG_IP_SCTP) += sctp/ +obj-$(CONFIG_KLIPS) += ipsec/ obj-$(CONFIG_IEEE80211) += ieee80211/ obj-$(CONFIG_TIPC) += tipc/ obj-$(CONFIG_NETLABEL) += netlabel/ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ac181be1..3f7d6212 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -773,6 +773,20 @@ out: return NF_STOLEN; } +/* + * We've finished passing through netfilter, so we can remove the fake dst. + * This is required by some lower layers, eg ip_gre + */ +static int br_nf_dev_queue_xmit_finish(struct sk_buff *skb) +{ + if (skb->dst == (struct dst_entry *)&__fake_rtable) { + dst_release(skb->dst); + skb->dst = NULL; + } + + return br_dev_queue_push_xmit(skb); +} + static int br_nf_dev_queue_xmit(struct sk_buff *skb) { if (skb->protocol == htons(ETH_P_IP) && @@ -780,7 +794,7 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) !skb_is_gso(skb)) return ip_fragment(skb, br_dev_queue_push_xmit); else - return br_dev_queue_push_xmit(skb); + return br_nf_dev_queue_xmit_finish(skb); } /* PF_BRIDGE/POST_ROUTING ********************************************/ diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 068d8afb..24aade46 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -124,35 +124,23 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) br_send_bpdu(p, buf, 4); } -/* - * Called from llc. - * - * NO locks, but rcu_read_lock (preempt_disabled) - */ -int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) +static void __br_stp_rcv(struct sk_buff *skb, struct net_device *dev, + const unsigned char *dest) { - const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = rcu_dereference(dev->br_port); struct net_bridge *br; const unsigned char *buf; if (!p) - goto err; - - if (pdu->ssap != LLC_SAP_BSPAN - || pdu->dsap != LLC_SAP_BSPAN - || pdu->ctrl_1 != LLC_PDU_TYPE_U) - goto err; + return; if (!pskb_may_pull(skb, 4)) - goto err; + return; /* compare of protocol id and version */ buf = skb->data; if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) - goto err; + return; br = p->br; spin_lock(&br->lock); @@ -162,7 +150,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, || !(br->dev->flags & IFF_UP)) goto out; - if (compare_ether_addr(dest, br->group_addr) != 0) + if (dest && compare_ether_addr(dest, br->group_addr) != 0) goto out; buf = skb_pull(skb, 3); @@ -213,7 +201,34 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, } out: spin_unlock(&br->lock); +} + +/* + * Called from llc. + * + * NO locks, but rcu_read_lock (preempt_disabled) + */ +int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + const unsigned char *dest = eth_hdr(skb)->h_dest; + + if (pdu->ssap != LLC_SAP_BSPAN + || pdu->dsap != LLC_SAP_BSPAN + || pdu->ctrl_1 != LLC_PDU_TYPE_U) + goto err; + + __br_stp_rcv(skb, dev, dest); + err: kfree_skb(skb); return 0; } + +void br_stp_rcv_raw(struct sk_buff *skb, struct net_device *dev) +{ + rcu_read_lock(); + __br_stp_rcv(skb, dev, NULL); + rcu_read_unlock(); +} diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b8b10635..75199441 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -147,6 +147,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, struct sk_buff *skb; u8 *data; +#if defined(CONFIG_ARCH_IXP4XX) + gfp_mask |= GFP_DMA; +#endif cache = fclone ? skbuff_fclone_cache : skbuff_head_cache; /* Get the HEAD */ diff --git a/net/ipsec/Makefile b/net/ipsec/Makefile new file mode 100644 index 00000000..04a444b2 --- /dev/null +++ b/net/ipsec/Makefile @@ -0,0 +1,24 @@ +.EXPORT_ALL_VARIABLES: + +OPENSWANSRCDIR := $(ROOTDIR)/openswan + +EXTRA_CFLAGS += -I$(OPENSWANSRCDIR) -I$(OPENSWANSRCDIR)/openswan/lib \ + -I$(OPENSWANSRCDIR)/linux/net/ipsec \ + -I$(OPENSWANSRCDIR)/linux/include \ + -I$(ROOTDIR)/modules/ocf + +$(obj)/.linked: + ln -fs $(OPENSWANSRCDIR)/linux/net/ipsec/*.[cS] $(obj)/. + touch $(obj)/.linked + +-include $(obj)/.linked + +include $(OPENSWANSRCDIR)/linux/net/ipsec/Makefile.fs2_6 + +$(obj)/version.c: $(OPENSWANSRCDIR)/linux/net/ipsec/version.in.c + sed '/"/s/xxx/$(IPSECVERSION)/' $? > $@ + +clean: + rm -f $(obj)/.linked $(obj)/*.o $(obj)/*.ko $(obj)/version.c + + diff --git a/net/ipsec/addrtoa.c b/net/ipsec/addrtoa.c new file mode 120000 index 00000000..27a8abd6 --- /dev/null +++ b/net/ipsec/addrtoa.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/addrtoa.c \ No newline at end of file diff --git a/net/ipsec/addrtot.c b/net/ipsec/addrtot.c new file mode 120000 index 00000000..f96f85c8 --- /dev/null +++ b/net/ipsec/addrtot.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/addrtot.c \ No newline at end of file diff --git a/net/ipsec/addrtypeof.c b/net/ipsec/addrtypeof.c new file mode 120000 index 00000000..0eeeeeb2 --- /dev/null +++ b/net/ipsec/addrtypeof.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/addrtypeof.c \ No newline at end of file diff --git a/net/ipsec/adler32.c b/net/ipsec/adler32.c new file mode 120000 index 00000000..a24e291a --- /dev/null +++ b/net/ipsec/adler32.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/adler32.c \ No newline at end of file diff --git a/net/ipsec/aes/Makefile b/net/ipsec/aes/Makefile new file mode 100644 index 00000000..a713ec66 --- /dev/null +++ b/net/ipsec/aes/Makefile @@ -0,0 +1,15 @@ +.EXPORT_ALL_VARIABLES: + +OPENSWANSRCDIR := $(ROOTDIR)/openswan + +EXTRA_CFLAGS += -I$(ROOTDIR)/openswan -I$(ROOTDIR)/openswan/lib \ + -I$(ROOTDIR)/openswan/linux/net/ipsec \ + -I$(ROOTDIR)/openswan/linux/include \ + -I$(ROOTDIR)/modules/ocf + +include $(ROOTDIR)/openswan/linux/net/ipsec/aes/Makefile.fs2_6 + +# special hack required because of exported object files +$(obj)%.c: $(ROOTDIR)/openswan/linux/net/ipsec/aes/%.c + ln -fs $< $@ + diff --git a/net/ipsec/anyaddr.c b/net/ipsec/anyaddr.c new file mode 120000 index 00000000..35dcb433 --- /dev/null +++ b/net/ipsec/anyaddr.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/anyaddr.c \ No newline at end of file diff --git a/net/ipsec/datatot.c b/net/ipsec/datatot.c new file mode 120000 index 00000000..a6dc08f2 --- /dev/null +++ b/net/ipsec/datatot.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/datatot.c \ No newline at end of file diff --git a/net/ipsec/deflate.c b/net/ipsec/deflate.c new file mode 120000 index 00000000..6415fe7d --- /dev/null +++ b/net/ipsec/deflate.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/deflate.c \ No newline at end of file diff --git a/net/ipsec/des/Makefile b/net/ipsec/des/Makefile new file mode 100644 index 00000000..3834204c --- /dev/null +++ b/net/ipsec/des/Makefile @@ -0,0 +1,22 @@ +.EXPORT_ALL_VARIABLES: + +OPENSWANSRCDIR := $(ROOTDIR)/openswan + +EXTRA_CFLAGS += -I$(OPENSWANSRCDIR) -I$(OPENSWANSRCDIR)/lib \ + -I$(OPENSWANSRCDIR)/linux/net/ipsec \ + -I$(OPENSWANSRCDIR)/linux/include \ + -I$(ROOTDIR)/modules/ocf + +# special hack required because of exported object files +$(obj)/.linked: + ln -fs $(OPENSWANSRCDIR)/linux/net/ipsec/des/*.[cS] $(obj)/. + touch $(obj)/.linked + +-include $(obj)/.linked + +include $(OPENSWANSRCDIR)/linux/net/ipsec/des/Makefile.fs2_6 + +clean: + rm -f $(obj)/.linked $(obj)/*.o $(obj)/*.ko + + diff --git a/net/ipsec/goodmask.c b/net/ipsec/goodmask.c new file mode 120000 index 00000000..231e859e --- /dev/null +++ b/net/ipsec/goodmask.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/goodmask.c \ No newline at end of file diff --git a/net/ipsec/infblock.c b/net/ipsec/infblock.c new file mode 120000 index 00000000..86ff5eb3 --- /dev/null +++ b/net/ipsec/infblock.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/infblock.c \ No newline at end of file diff --git a/net/ipsec/infcodes.c b/net/ipsec/infcodes.c new file mode 120000 index 00000000..5c9e0e67 --- /dev/null +++ b/net/ipsec/infcodes.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/infcodes.c \ No newline at end of file diff --git a/net/ipsec/inffast.c b/net/ipsec/inffast.c new file mode 120000 index 00000000..d7c1ae67 --- /dev/null +++ b/net/ipsec/inffast.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/inffast.c \ No newline at end of file diff --git a/net/ipsec/inflate.c b/net/ipsec/inflate.c new file mode 120000 index 00000000..94a8d307 --- /dev/null +++ b/net/ipsec/inflate.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/inflate.c \ No newline at end of file diff --git a/net/ipsec/inftrees.c b/net/ipsec/inftrees.c new file mode 120000 index 00000000..3f704b93 --- /dev/null +++ b/net/ipsec/inftrees.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/inftrees.c \ No newline at end of file diff --git a/net/ipsec/infutil.c b/net/ipsec/infutil.c new file mode 120000 index 00000000..023c2767 --- /dev/null +++ b/net/ipsec/infutil.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/infutil.c \ No newline at end of file diff --git a/net/ipsec/initaddr.c b/net/ipsec/initaddr.c new file mode 120000 index 00000000..8f9209b1 --- /dev/null +++ b/net/ipsec/initaddr.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/initaddr.c \ No newline at end of file diff --git a/net/ipsec/ipcomp.c b/net/ipsec/ipcomp.c new file mode 120000 index 00000000..f1ae45e3 --- /dev/null +++ b/net/ipsec/ipcomp.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipcomp.c \ No newline at end of file diff --git a/net/ipsec/ipsec_ah.c b/net/ipsec/ipsec_ah.c new file mode 120000 index 00000000..31afffe2 --- /dev/null +++ b/net/ipsec/ipsec_ah.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_ah.c \ No newline at end of file diff --git a/net/ipsec/ipsec_alg.c b/net/ipsec/ipsec_alg.c new file mode 120000 index 00000000..a600d19e --- /dev/null +++ b/net/ipsec/ipsec_alg.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_alg.c \ No newline at end of file diff --git a/net/ipsec/ipsec_alg_cryptoapi.c b/net/ipsec/ipsec_alg_cryptoapi.c new file mode 120000 index 00000000..d8337bda --- /dev/null +++ b/net/ipsec/ipsec_alg_cryptoapi.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_alg_cryptoapi.c \ No newline at end of file diff --git a/net/ipsec/ipsec_esp.c b/net/ipsec/ipsec_esp.c new file mode 120000 index 00000000..059f4c80 --- /dev/null +++ b/net/ipsec/ipsec_esp.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_esp.c \ No newline at end of file diff --git a/net/ipsec/ipsec_init.c b/net/ipsec/ipsec_init.c new file mode 120000 index 00000000..1c46961c --- /dev/null +++ b/net/ipsec/ipsec_init.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_init.c \ No newline at end of file diff --git a/net/ipsec/ipsec_ipcomp.c b/net/ipsec/ipsec_ipcomp.c new file mode 120000 index 00000000..a6e174e9 --- /dev/null +++ b/net/ipsec/ipsec_ipcomp.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_ipcomp.c \ No newline at end of file diff --git a/net/ipsec/ipsec_ipip.c b/net/ipsec/ipsec_ipip.c new file mode 120000 index 00000000..afde1091 --- /dev/null +++ b/net/ipsec/ipsec_ipip.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_ipip.c \ No newline at end of file diff --git a/net/ipsec/ipsec_kern24.c b/net/ipsec/ipsec_kern24.c new file mode 120000 index 00000000..8073bbb6 --- /dev/null +++ b/net/ipsec/ipsec_kern24.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_kern24.c \ No newline at end of file diff --git a/net/ipsec/ipsec_life.c b/net/ipsec/ipsec_life.c new file mode 120000 index 00000000..0abd4e92 --- /dev/null +++ b/net/ipsec/ipsec_life.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_life.c \ No newline at end of file diff --git a/net/ipsec/ipsec_mast.c b/net/ipsec/ipsec_mast.c new file mode 120000 index 00000000..9ba9dc23 --- /dev/null +++ b/net/ipsec/ipsec_mast.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_mast.c \ No newline at end of file diff --git a/net/ipsec/ipsec_md5c.c b/net/ipsec/ipsec_md5c.c new file mode 120000 index 00000000..835b8c6d --- /dev/null +++ b/net/ipsec/ipsec_md5c.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_md5c.c \ No newline at end of file diff --git a/net/ipsec/ipsec_ocf.c b/net/ipsec/ipsec_ocf.c new file mode 120000 index 00000000..99f3a4cc --- /dev/null +++ b/net/ipsec/ipsec_ocf.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_ocf.c \ No newline at end of file diff --git a/net/ipsec/ipsec_proc.c b/net/ipsec/ipsec_proc.c new file mode 120000 index 00000000..4fc2de6b --- /dev/null +++ b/net/ipsec/ipsec_proc.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_proc.c \ No newline at end of file diff --git a/net/ipsec/ipsec_radij.c b/net/ipsec/ipsec_radij.c new file mode 120000 index 00000000..2cd46165 --- /dev/null +++ b/net/ipsec/ipsec_radij.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_radij.c \ No newline at end of file diff --git a/net/ipsec/ipsec_rcv.c b/net/ipsec/ipsec_rcv.c new file mode 120000 index 00000000..eeea96d3 --- /dev/null +++ b/net/ipsec/ipsec_rcv.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_rcv.c \ No newline at end of file diff --git a/net/ipsec/ipsec_sa.c b/net/ipsec/ipsec_sa.c new file mode 120000 index 00000000..7d570b60 --- /dev/null +++ b/net/ipsec/ipsec_sa.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_sa.c \ No newline at end of file diff --git a/net/ipsec/ipsec_sha1.c b/net/ipsec/ipsec_sha1.c new file mode 120000 index 00000000..da258558 --- /dev/null +++ b/net/ipsec/ipsec_sha1.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_sha1.c \ No newline at end of file diff --git a/net/ipsec/ipsec_snprintf.c b/net/ipsec/ipsec_snprintf.c new file mode 120000 index 00000000..13003b0d --- /dev/null +++ b/net/ipsec/ipsec_snprintf.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_snprintf.c \ No newline at end of file diff --git a/net/ipsec/ipsec_tunnel.c b/net/ipsec/ipsec_tunnel.c new file mode 120000 index 00000000..0da562ff --- /dev/null +++ b/net/ipsec/ipsec_tunnel.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_tunnel.c \ No newline at end of file diff --git a/net/ipsec/ipsec_xform.c b/net/ipsec/ipsec_xform.c new file mode 120000 index 00000000..b6590031 --- /dev/null +++ b/net/ipsec/ipsec_xform.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_xform.c \ No newline at end of file diff --git a/net/ipsec/ipsec_xmit.c b/net/ipsec/ipsec_xmit.c new file mode 120000 index 00000000..c311f950 --- /dev/null +++ b/net/ipsec/ipsec_xmit.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ipsec_xmit.c \ No newline at end of file diff --git a/net/ipsec/match586.S b/net/ipsec/match586.S new file mode 120000 index 00000000..6774bc36 --- /dev/null +++ b/net/ipsec/match586.S @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/match586.S \ No newline at end of file diff --git a/net/ipsec/match686.S b/net/ipsec/match686.S new file mode 120000 index 00000000..ad106cc7 --- /dev/null +++ b/net/ipsec/match686.S @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/match686.S \ No newline at end of file diff --git a/net/ipsec/pfkey_v2.c b/net/ipsec/pfkey_v2.c new file mode 120000 index 00000000..557c34ec --- /dev/null +++ b/net/ipsec/pfkey_v2.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_build.c b/net/ipsec/pfkey_v2_build.c new file mode 120000 index 00000000..63a2741f --- /dev/null +++ b/net/ipsec/pfkey_v2_build.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_build.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_debug.c b/net/ipsec/pfkey_v2_debug.c new file mode 120000 index 00000000..d550864e --- /dev/null +++ b/net/ipsec/pfkey_v2_debug.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_debug.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_ext_bits.c b/net/ipsec/pfkey_v2_ext_bits.c new file mode 120000 index 00000000..898c3a51 --- /dev/null +++ b/net/ipsec/pfkey_v2_ext_bits.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_ext_bits.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_ext_process.c b/net/ipsec/pfkey_v2_ext_process.c new file mode 120000 index 00000000..5e74d2a5 --- /dev/null +++ b/net/ipsec/pfkey_v2_ext_process.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_ext_process.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_parse.c b/net/ipsec/pfkey_v2_parse.c new file mode 120000 index 00000000..85b2077e --- /dev/null +++ b/net/ipsec/pfkey_v2_parse.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_parse.c \ No newline at end of file diff --git a/net/ipsec/pfkey_v2_parser.c b/net/ipsec/pfkey_v2_parser.c new file mode 120000 index 00000000..22d9b6e0 --- /dev/null +++ b/net/ipsec/pfkey_v2_parser.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/pfkey_v2_parser.c \ No newline at end of file diff --git a/net/ipsec/prng.c b/net/ipsec/prng.c new file mode 120000 index 00000000..3fb0e828 --- /dev/null +++ b/net/ipsec/prng.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/prng.c \ No newline at end of file diff --git a/net/ipsec/radij.c b/net/ipsec/radij.c new file mode 120000 index 00000000..9ce5ec3d --- /dev/null +++ b/net/ipsec/radij.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/radij.c \ No newline at end of file diff --git a/net/ipsec/rangetoa.c b/net/ipsec/rangetoa.c new file mode 120000 index 00000000..0bcc5c75 --- /dev/null +++ b/net/ipsec/rangetoa.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/rangetoa.c \ No newline at end of file diff --git a/net/ipsec/satot.c b/net/ipsec/satot.c new file mode 120000 index 00000000..621ecd1c --- /dev/null +++ b/net/ipsec/satot.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/satot.c \ No newline at end of file diff --git a/net/ipsec/subnetof.c b/net/ipsec/subnetof.c new file mode 120000 index 00000000..f05a5e02 --- /dev/null +++ b/net/ipsec/subnetof.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/subnetof.c \ No newline at end of file diff --git a/net/ipsec/subnettoa.c b/net/ipsec/subnettoa.c new file mode 120000 index 00000000..cdc0b9a4 --- /dev/null +++ b/net/ipsec/subnettoa.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/subnettoa.c \ No newline at end of file diff --git a/net/ipsec/sysctl_net_ipsec.c b/net/ipsec/sysctl_net_ipsec.c new file mode 120000 index 00000000..39134ed3 --- /dev/null +++ b/net/ipsec/sysctl_net_ipsec.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/sysctl_net_ipsec.c \ No newline at end of file diff --git a/net/ipsec/trees.c b/net/ipsec/trees.c new file mode 120000 index 00000000..45ce9658 --- /dev/null +++ b/net/ipsec/trees.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/trees.c \ No newline at end of file diff --git a/net/ipsec/ultoa.c b/net/ipsec/ultoa.c new file mode 120000 index 00000000..4017ab99 --- /dev/null +++ b/net/ipsec/ultoa.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ultoa.c \ No newline at end of file diff --git a/net/ipsec/ultot.c b/net/ipsec/ultot.c new file mode 120000 index 00000000..146862d6 --- /dev/null +++ b/net/ipsec/ultot.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/ultot.c \ No newline at end of file diff --git a/net/ipsec/version.in.c b/net/ipsec/version.in.c new file mode 120000 index 00000000..be0afce0 --- /dev/null +++ b/net/ipsec/version.in.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/version.in.c \ No newline at end of file diff --git a/net/ipsec/zutil.c b/net/ipsec/zutil.c new file mode 120000 index 00000000..ae6c18a2 --- /dev/null +++ b/net/ipsec/zutil.c @@ -0,0 +1 @@ +/home/work/uclinux-moxaart/openswan/linux/net/ipsec/zutil.c \ No newline at end of file diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5572071a..12ecec67 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -416,6 +416,12 @@ config INET_TUNNEL tristate default n +config IPSEC_NAT_TRAVERSAL + bool "IPSEC NAT-Traversal (KLIPS compatible)" + depends on INET + ---help--- + Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP. + config INET_XFRM_MODE_TRANSPORT tristate "IP: IPsec transport mode" default y diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index edcf0932..f9cca92f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1326,6 +1326,18 @@ static int __init inet_init(void) #if defined(CONFIG_IP_MROUTE) ip_mr_init(); #endif + +#if defined(CONFIG_KLIPS) + { + extern int ipsec_klips_init(void); + /* + * Initialise AF_INET ESP and AH protocol support including + * e-routing and SA tables + */ + ipsec_klips_init(); + } +#endif /* CONFIG_IPSEC */ + /* * Initialise per-cpu ipv4 mibs */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d5b5dec0..69049813 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include @@ -118,6 +121,7 @@ static int ipgre_tunnel_init(struct net_device *dev); static void ipgre_tunnel_setup(struct net_device *dev); +static void ipgre_ether_tunnel_setup(struct net_device *dev); /* Fallback tunnel: no source, no destination, no key, no options */ @@ -273,7 +277,10 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int goto failed; } - dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); + if (parms->iph.id == htons(ETH_P_BRIDGE)) + dev = alloc_netdev(sizeof(*t), name, ipgre_ether_tunnel_setup); + else + dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); if (!dev) return NULL; @@ -552,6 +559,23 @@ ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb) return INET_ECN_encapsulate(tos, inner); } +static __be16 ipgre_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + if (skb->protocol == htons(ETH_P_BRIDGE)) { + if (!pskb_may_pull(skb, ETH_HLEN)) + return 0; + return eth_type_trans(skb, dev); + } +#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) + else if (skb->protocol == htons(LLC_SAP_BSPAN)) { + br_stp_rcv_raw(skb, dev); + return 0; + } +#endif + + return 0; +} + static int ipgre_rcv(struct sk_buff *skb) { struct iphdr *iph; @@ -646,6 +670,13 @@ static int ipgre_rcv(struct sk_buff *skb) } tunnel->i_seqno = seqno + 1; } + if (tunnel->dev->type == ARPHRD_ETHER) { + skb->protocol = ipgre_type_trans(skb, tunnel->dev); + if (!skb->protocol) { + tunnel->stat.rx_errors++; + goto drop; + } + } tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; skb->dev = tunnel->dev; @@ -679,6 +710,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ int gre_hlen; + int push_hlen; u32 dst; int mtu; @@ -687,11 +719,18 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_error; } - if (dev->hard_header) { - gre_hlen = 0; + if (dev->type == ARPHRD_ETHER) { + skb->protocol = htons(ETH_P_BRIDGE); + gre_hlen = tunnel->hlen - ETH_HLEN; + push_hlen = gre_hlen; + tiph = &tunnel->parms.iph; + } else if (dev->hard_header) { + gre_hlen = tunnel->hlen; + push_hlen = 0; tiph = (struct iphdr*)skb->data; } else { gre_hlen = tunnel->hlen; + push_hlen = gre_hlen; tiph = &tunnel->parms.iph; } @@ -793,7 +832,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) { + if (mtu >= IPV6_MIN_MTU && + mtu < skb->len - tunnel->hlen + push_hlen) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); ip_rt_put(rt); goto tx_error; @@ -810,7 +850,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) tunnel->err_count = 0; } - max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen; + max_headroom = LL_RESERVED_SPACE(tdev) + push_hlen; if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); @@ -829,7 +869,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } skb->h.raw = skb->nh.raw; - skb->nh.raw = skb_push(skb, gre_hlen); + skb->nh.raw = skb_push(skb, push_hlen); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); @@ -864,7 +904,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ((u16*)(iph+1))[1] = skb->protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { - u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); + u32 *ptr = (u32*)(((u8*)iph) + gre_hlen - 4); if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; @@ -936,6 +976,8 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) || ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))) goto done; + if (p.iph.id != 0 && p.iph.id != htons(ETH_P_BRIDGE)) + goto done; if (p.iph.ttl) p.iph.frag_off |= htons(IP_DF); @@ -957,7 +999,9 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = netdev_priv(dev); - if (MULTICAST(p.iph.daddr)) + if (t->dev->type == ARPHRD_ETHER) + nflags = IFF_BROADCAST; + else if (MULTICAST(p.iph.daddr)) nflags = IFF_BROADCAST; else if (p.iph.daddr) nflags = IFF_POINTOPOINT; @@ -1148,6 +1192,18 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->addr_len = 4; } +static void ipgre_ether_tunnel_setup(struct net_device *dev) +{ + ether_setup(dev); + + SET_MODULE_OWNER(dev); + dev->uninit = ipgre_tunnel_uninit; + dev->destructor = free_netdev; + dev->hard_start_xmit = ipgre_tunnel_xmit; + dev->get_stats = ipgre_tunnel_get_stats; + dev->do_ioctl = ipgre_tunnel_ioctl; +} + static int ipgre_tunnel_init(struct net_device *dev) { struct net_device *tdev = NULL; @@ -1163,8 +1219,27 @@ static int ipgre_tunnel_init(struct net_device *dev) tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); - memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); - memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); + if (dev->type == ARPHRD_ETHER) + random_ether_addr(dev->dev_addr); + else { + memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); + memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); + } + + if (dev->type == ARPHRD_ETHER) + dev->flags |= IFF_BROADCAST; +#ifdef CONFIG_NET_IPGRE_BROADCAST + else if (MULTICAST(iph->daddr)) { + if (!iph->saddr) + return -EINVAL; + dev->flags = IFF_BROADCAST; + dev->hard_header = ipgre_header; + dev->open = ipgre_open; + dev->stop = ipgre_close; + } +#endif + else if (iph->daddr) + dev->flags |= IFF_POINTOPOINT; /* Guess output device to choose reasonable mtu and hard_header_len */ @@ -1180,19 +1255,6 @@ static int ipgre_tunnel_init(struct net_device *dev) tdev = rt->u.dst.dev; ip_rt_put(rt); } - - dev->flags |= IFF_POINTOPOINT; - -#ifdef CONFIG_NET_IPGRE_BROADCAST - if (MULTICAST(iph->daddr)) { - if (!iph->saddr) - return -EINVAL; - dev->flags = IFF_BROADCAST; - dev->hard_header = ipgre_header; - dev->open = ipgre_open; - dev->stop = ipgre_close; - } -#endif } if (!tdev && tunnel->parms.link) @@ -1213,6 +1275,8 @@ static int ipgre_tunnel_init(struct net_device *dev) if (tunnel->parms.o_flags&GRE_SEQ) addend += 4; } + if (dev->type == ARPHRD_ETHER) + addend += ETH_HLEN; dev->hard_header_len = hlen + addend; dev->mtu = mtu - addend; tunnel->hlen = addend; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index d88c292f..420f26e8 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -248,6 +248,24 @@ config IP_NF_MATCH_IPRANGE To compile it as a module, choose M here. If unsure, say N. +config IP_NF_MATCH_LAYER7 + tristate "Layer 7 match support (EXPERIMENTAL)" + depends on IP_NF_IPTABLES && IP_NF_CT_ACCT && IP_NF_CONNTRACK && EXPERIMENTAL + help + Say Y if you want to be able to classify connections (and their + packets) based on regular expression matching of their application + layer data. This is one way to classify applications such as + peer-to-peer filesharing systems that do not always use the same + port. + + To compile it as a module, choose M here. If unsure, say N. + +config IP_NF_MATCH_LAYER7_DEBUG + bool "Layer 7 debugging output" + depends on IP_NF_MATCH_LAYER7 + help + Say Y to get lots of debugging output. + config IP_NF_MATCH_TOS tristate "TOS match support" depends on IP_NF_IPTABLES @@ -329,6 +347,27 @@ config IP_NF_MATCH_HASHLIMIT destination IP' or `500pps from any given source IP' with a single IPtables rule. +config IP_NF_MATCH_POLICY + tristate "IPsec policy match support" + depends on IP_NF_IPTABLES && XFRM + help + Policy matching allows you to match packets based on the + IPsec policy that was used during decapsulation/will + be used during encapsulation. + + To compile it as a module, choose M here. If unsure, say N. + +config IP_NF_MATCH_TIME + tristate 'TIME match support' + depends on IP_NF_IPTABLES + help + This option adds a `time' match, which allows you + to match based on the packet arrival time/date + (arrival time/date at the machine which netfilter is running on) or + departure time/date (for locally generated packets). + + To compile it as a module, choose M here. If unsure, say N. + # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 09aaed1a..b5f26456 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -62,6 +62,10 @@ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o +obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o + +obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o # targets obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 8b848aa7..b954cb37 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -337,6 +337,13 @@ destroy_conntrack(struct nf_conntrack *nfct) * too. */ ip_ct_remove_expectations(ct); + #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + if(ct->layer7.app_proto) + kfree(ct->layer7.app_proto); + if(ct->layer7.app_data) + kfree(ct->layer7.app_data); + #endif + /* We overload first tuple to link into unconfirmed list. */ if (!is_confirmed(ct)) { BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list)); diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 93dcf960..0eac6c16 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -413,8 +413,14 @@ static int help(struct sk_buff **pskb, problem (DMZ machines opening holes to internal networks, or the packet filter itself). */ if (!loose) { - ret = NF_ACCEPT; - goto out_put_expect; + if (net_ratelimit()) + printk("conntrack_ftp: ip mismatch: " + "%u,%u,%u,%u != %u.%u.%u.%u\n", + array[0], array[1], array[2], array[3], + NIPQUAD(ct->tuplehash[dir].tuple.src.ip)); + ret = NF_DROP; + ip_conntrack_expect_put(exp); + goto out; } exp->tuple.dst.ip = htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]); @@ -444,7 +450,6 @@ static int help(struct sk_buff **pskb, ret = NF_ACCEPT; } -out_put_expect: ip_conntrack_expect_put(exp); out_update_nl: diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 02135756..bdd1b7da 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -192,6 +192,12 @@ static int ct_seq_show(struct seq_file *s, void *v) return -ENOSPC; #endif +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + if(conntrack->layer7.app_proto) + if (seq_printf(s, "l7proto=%s ",conntrack->layer7.app_proto)) + return 1; +#endif + if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) return -ENOSPC; diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index d85d2de5..77e7e911 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -37,6 +37,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -122,8 +123,13 @@ ip_nat_fn(unsigned int hooknum, (*pskb)->nh.iph->ihl*4, sizeof(_hdr), &_hdr); if (hp != NULL && - hp->type == ICMP_REDIRECT) + hp->type == ICMP_REDIRECT) { + if (LOG_INVALID(IPPROTO_ICMP)) + nf_log_packet(PF_INET, 0, *pskb, + NULL, NULL, NULL, "ip_nat_fn: " + "untracked ICMP redirect "); return NF_DROP; + } } return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 108b6b76..8207882f 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -21,6 +21,22 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); MODULE_DESCRIPTION("iptables TCP MSS modification module"); +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define HDRSIZE (sizeof(struct iphdr) + sizeof(struct tcphdr)) + +static u_int16_t +cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) +{ + u_int32_t diffs[] = { oldvalinv, newval }; + return csum_fold(csum_partial((char *)diffs, sizeof(diffs), + oldcheck^0xFFFF)); +} + static inline unsigned int optlen(const u_int8_t *opt, unsigned int offset) { @@ -64,7 +80,7 @@ ipt_tcpmss_target(struct sk_buff **pskb, printk(KERN_ERR "ipt_tcpmss_target: bad length (%d bytes)\n", (*pskb)->len); - return NF_DROP; + return IPT_CONTINUE; } if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { diff --git a/net/ipv4/netfilter/ipt_layer7.c b/net/ipv4/netfilter/ipt_layer7.c new file mode 100644 index 00000000..db9f692d --- /dev/null +++ b/net/ipv4/netfilter/ipt_layer7.c @@ -0,0 +1,580 @@ +/* + Kernel module to match application layer (OSI layer 7) + data in connections. + + http://l7-filter.sf.net + + By Matthew Strait and Ethan Sommer, 2003-2005. + + 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. + http://www.gnu.org/licenses/gpl.txt + + Based on ipt_string.c (C) 2000 Emmanuel Roger + and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "regexp/regexp.c" + +#include +#include + +MODULE_AUTHOR("Matthew Strait , Ethan Sommer "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iptables application layer match module"); +MODULE_VERSION("2.0"); + +static int maxdatalen = 2048; // this is the default +module_param(maxdatalen, int, 0444); +MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter"); + +#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG + #define DPRINTK(format,args...) printk(format,##args) +#else + #define DPRINTK(format,args...) +#endif + +#define TOTAL_PACKETS master_conntrack->counters[IP_CT_DIR_ORIGINAL].packets + \ + master_conntrack->counters[IP_CT_DIR_REPLY].packets + +/* Number of packets whose data we look at. +This can be modified through /proc/net/layer7_numpackets */ +static int num_packets = 10; + +static struct pattern_cache { + char * regex_string; + regexp * pattern; + struct pattern_cache * next; +} * first_pattern_cache = NULL; + +/* I'm new to locking. Here are my assumptions: + +- No one will write to /proc/net/layer7_numpackets over and over very fast; + if they did, nothing awful would happen. + +- This code will never be processing the same packet twice at the same time, + because iptables rules are traversed in order. + +- It doesn't matter if two packets from different connections are in here at + the same time, because they don't share any data. + +- It _does_ matter if two packets from the same connection (or one from a + master and one from its child) are here at the same time. In this case, + we have to protect the conntracks and the list of compiled patterns. +*/ +DEFINE_RWLOCK(ct_lock); +DEFINE_SPINLOCK(list_lock); + +#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG +/* Converts an unfriendly string into a friendly one by +replacing unprintables with periods and all whitespace with " ". */ +static char * friendly_print(unsigned char * s) +{ + char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); + int i; + + if(!f) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n"); + return NULL; + } + + for(i = 0; i < strlen(s); i++){ + if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; + else if(isspace(s[i])) f[i] = ' '; + else f[i] = '.'; + } + f[i] = '\0'; + return f; +} + +static char dec2hex(int i) +{ + switch (i) { + case 0 ... 9: + return (char)(i + '0'); + break; + case 10 ... 15: + return (char)(i - 10 + 'a'); + break; + default: + if (net_ratelimit()) + printk("Problem in dec2hex\n"); + return '\0'; + } +} + +static char * hex_print(unsigned char * s) +{ + char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); + int i; + + if(!g) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n"); + return NULL; + } + + for(i = 0; i < strlen(s); i++) { + g[i*3 ] = dec2hex(s[i]/16); + g[i*3 + 1] = dec2hex(s[i]%16); + g[i*3 + 2] = ' '; + } + g[i*3] = '\0'; + + return g; +} +#endif // DEBUG + +/* Use instead of regcomp. As we expect to be seeing the same regexps over and +over again, it make sense to cache the results. */ +static regexp * compile_and_cache(char * regex_string, char * protocol) +{ + struct pattern_cache * node = first_pattern_cache; + struct pattern_cache * last_pattern_cache = first_pattern_cache; + struct pattern_cache * tmp; + unsigned int len; + + while (node != NULL) { + if (!strcmp(node->regex_string, regex_string)) + return node->pattern; + + last_pattern_cache = node;/* points at the last non-NULL node */ + node = node->next; + } + + /* If we reach the end of the list, then we have not yet cached + the pattern for this regex. Let's do that now. + Be paranoid about running out of memory to avoid list corruption. */ + tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); + + if(!tmp) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); + return NULL; + } + + tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); + tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); + tmp->next = NULL; + + if(!tmp->regex_string || !tmp->pattern) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); + kfree(tmp->regex_string); + kfree(tmp->pattern); + kfree(tmp); + return NULL; + } + + /* Ok. The new node is all ready now. */ + node = tmp; + + if(first_pattern_cache == NULL) /* list is empty */ + first_pattern_cache = node; /* make node the beginning */ + else + last_pattern_cache->next = node; /* attach node to the end */ + + /* copy the string and compile the regex */ + len = strlen(regex_string); + DPRINTK("About to compile this: \"%s\"\n", regex_string); + node->pattern = regcomp(regex_string, &len); + if ( !node->pattern ) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol); + /* pattern is now cached as NULL, so we won't try again. */ + } + + strcpy(node->regex_string, regex_string); + return node->pattern; +} + +static int can_handle(const struct sk_buff *skb) +{ + if(!skb->nh.iph) /* not IP */ + return 0; + if(skb->nh.iph->protocol != IPPROTO_TCP && + skb->nh.iph->protocol != IPPROTO_UDP && + skb->nh.iph->protocol != IPPROTO_ICMP) + return 0; + return 1; +} + +/* Returns offset the into the skb->data that the application data starts */ +static int app_data_offset(const struct sk_buff *skb) +{ + /* In case we are ported somewhere (ebtables?) where skb->nh.iph + isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ + int ip_hl = 4*skb->nh.iph->ihl; + + if( skb->nh.iph->protocol == IPPROTO_TCP ) { + /* 12 == offset into TCP header for the header length field. + Can't get this with skb->h.th->doff because the tcphdr + struct doesn't get set when routing (this is confirmed to be + true in Netfilter as well as QoS.) */ + int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); + + return ip_hl + tcp_hl; + } else if( skb->nh.iph->protocol == IPPROTO_UDP ) { + return ip_hl + 8; /* UDP header is always 8 bytes */ + } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { + return ip_hl + 8; /* ICMP header is 8 bytes */ + } else { + if (net_ratelimit()) + printk(KERN_ERR "layer7: tried to handle unknown protocol!\n"); + return ip_hl + 8; /* something reasonable */ + } +} + +/* handles whether there's a match when we aren't appending data anymore */ +static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack, + enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo, + struct ipt_layer7_info * info) +{ + /* If we're in here, throw the app data away */ + write_lock(&ct_lock); + if(master_conntrack->layer7.app_data != NULL) { + + #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG + if(!master_conntrack->layer7.app_proto) { + char * f = friendly_print(master_conntrack->layer7.app_data); + char * g = hex_print(master_conntrack->layer7.app_data); + DPRINTK("\nl7-filter gave up after %d bytes (%d packets):\n%s\n", + strlen(f), TOTAL_PACKETS, f); + kfree(f); + DPRINTK("In hex: %s\n", g); + kfree(g); + } + #endif + + kfree(master_conntrack->layer7.app_data); + master_conntrack->layer7.app_data = NULL; /* don't free again */ + } + write_unlock(&ct_lock); + + if(master_conntrack->layer7.app_proto){ + /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */ + write_lock(&ct_lock); + if(!conntrack->layer7.app_proto) { + conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC); + if(!conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); + write_unlock(&ct_lock); + return 1; + } + strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto); + } + write_unlock(&ct_lock); + + return (!strcmp(master_conntrack->layer7.app_proto, info->protocol)); + } + else { + /* If not classified, set to "unknown" to distinguish from + connections that are still being tested. */ + write_lock(&ct_lock); + master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC); + if(!master_conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); + write_unlock(&ct_lock); + return 1; + } + strcpy(master_conntrack->layer7.app_proto, "unknown"); + write_unlock(&ct_lock); + return 0; + } +} + +/* add the new app data to the conntrack. Return number of bytes added. */ +static int add_data(struct ip_conntrack * master_conntrack, + char * app_data, int appdatalen) +{ + int length = 0, i; + int oldlength = master_conntrack->layer7.app_data_len; + + // This is a fix for a race condition by Deti Fliegl. However, I'm not + // clear on whether the race condition exists or whether this really + // fixes it. I might just be being dense... Anyway, if it's not really + // a fix, all it does is waste a very small amount of time. + if(!master_conntrack->layer7.app_data) return 0; + + /* Strip nulls. Make everything lower case (our regex lib doesn't + do case insensitivity). Add it to the end of the current data. */ + for(i = 0; i < maxdatalen-oldlength-1 && + i < appdatalen; i++) { + if(app_data[i] != '\0') { + master_conntrack->layer7.app_data[length+oldlength] = + /* the kernel version of tolower mungs 'upper ascii' */ + isascii(app_data[i])? tolower(app_data[i]) : app_data[i]; + length++; + } + } + + master_conntrack->layer7.app_data[length+oldlength] = '\0'; + master_conntrack->layer7.app_data_len = length + oldlength; + + return length; +} + +/* Returns true on match and false otherwise. */ +static int match(const struct sk_buff *skb_const, + const struct net_device *in, const struct net_device *out, + const struct xt_match *match, const void *matchinfo, + int offset, unsigned int protoff, int *hotdrop) +{ + struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; + enum ip_conntrack_info master_ctinfo, ctinfo; + struct ip_conntrack *master_conntrack, *conntrack; + unsigned char * app_data; + unsigned int pattern_result, appdatalen; + regexp * comppattern; + struct sk_buff *skb = (struct sk_buff *)skb_const; /* see note below */ + + if(!can_handle(skb)){ + DPRINTK("layer7: This is some protocol I can't handle.\n"); + return info->invert; + } + + /* Treat parent & all its children together as one connection, except + for the purpose of setting conntrack->layer7.app_proto in the actual + connection. This makes /proc/net/ip_conntrack more satisfying. */ + if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || + !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { + //DPRINTK("layer7: packet is not from a known connection, giving up.\n"); + return info->invert; + } + + /* Try to get a master conntrack (and its master etc) for FTP, etc. */ + while (master_ct(master_conntrack) != NULL) + master_conntrack = master_ct(master_conntrack); + + /* if we've classified it or seen too many packets */ + if(TOTAL_PACKETS > num_packets || + master_conntrack->layer7.app_proto) { + + pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info); + + /* skb->cb[0] == seen. Avoid doing things twice if there are two l7 + rules. I'm not sure that using cb for this purpose is correct, although + it says "put your private variables there". But it doesn't look like it + is being used for anything else in the skbs that make it here. How can + I write to cb without making the compiler angry? */ + skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */ + + return (pattern_result ^ info->invert); + } + + if(skb_is_nonlinear(skb)){ + if(skb_linearize(skb) != 0){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n"); + return info->invert; + } + } + + /* now that the skb is linearized, it's safe to set these. */ + app_data = skb->data + app_data_offset(skb); + appdatalen = skb->tail - app_data; + + spin_lock_bh(&list_lock); + /* the return value gets checked later, when we're ready to use it */ + comppattern = compile_and_cache(info->pattern, info->protocol); + spin_unlock_bh(&list_lock); + + /* On the first packet of a connection, allocate space for app data */ + write_lock(&ct_lock); + if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) { + master_conntrack->layer7.app_data = kmalloc(maxdatalen, GFP_ATOMIC); + if(!master_conntrack->layer7.app_data){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); + write_unlock(&ct_lock); + return info->invert; + } + + master_conntrack->layer7.app_data[0] = '\0'; + } + write_unlock(&ct_lock); + + /* Can be here, but unallocated, if numpackets is increased near + the beginning of a connection */ + if(master_conntrack->layer7.app_data == NULL) + return (info->invert); /* unmatched */ + + if(!skb->cb[0]){ + int newbytes; + write_lock(&ct_lock); + newbytes = add_data(master_conntrack, app_data, appdatalen); + write_unlock(&ct_lock); + + if(newbytes == 0) { /* didn't add any data */ + skb->cb[0] = 1; + /* Didn't match before, not going to match now */ + return info->invert; + } + } + + /* If looking for "unknown", then never match. "Unknown" means that + we've given up; we're still trying with these packets. */ + read_lock(&ct_lock); + if(!strcmp(info->protocol, "unknown")) { + pattern_result = 0; + /* If the regexp failed to compile, don't bother running it */ + } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { + DPRINTK("layer7: matched %s\n", info->protocol); + pattern_result = 1; + } else pattern_result = 0; + read_unlock(&ct_lock); + + if(pattern_result) { + write_lock(&ct_lock); + master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); + if(!master_conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); + write_unlock(&ct_lock); + return (pattern_result ^ info->invert); + } + strcpy(master_conntrack->layer7.app_proto, info->protocol); + write_unlock(&ct_lock); + } + + /* mark the packet seen */ + skb->cb[0] = 1; + + return (pattern_result ^ info->invert); +} + +static int checkentry(const char *tablename, const void *ip, + const struct xt_match *match, void *matchinfo, + unsigned int hook_mask) +{ +// struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; + + return 1; +} + +static struct ipt_match layer7_match = { + .name = "layer7", + .match = &match, + .checkentry = &checkentry, + .matchsize = sizeof(struct ipt_layer7_info), + .me = THIS_MODULE +}; + +/* taken from drivers/video/modedb.c */ +static int my_atoi(const char *s) +{ + int val = 0; + + for (;; s++) { + switch (*s) { + case '0'...'9': + val = 10*val+(*s-'0'); + break; + default: + return val; + } + } +} + +/* write out num_packets to userland. */ +static int layer7_read_proc(char* page, char ** start, off_t off, int count, + int* eof, void * data) +{ + if(num_packets > 99 && net_ratelimit()) + printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); + + page[0] = num_packets/10 + '0'; + page[1] = num_packets%10 + '0'; + page[2] = '\n'; + page[3] = '\0'; + + *eof=1; + + return 3; +} + +/* Read in num_packets from userland */ +static int layer7_write_proc(struct file* file, const char* buffer, + unsigned long count, void *data) +{ + char * foo = kmalloc(count, GFP_ATOMIC); + + if(!foo){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n"); + return count; + } + + if(copy_from_user(foo, buffer, count)) { + return -EFAULT; + } + + + num_packets = my_atoi(foo); + kfree (foo); + + /* This has an arbitrary limit to make the math easier. I'm lazy. + But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ + if(num_packets > 99) { + printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); + num_packets = 99; + } else if(num_packets < 1) { + printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); + num_packets = 1; + } + + return count; +} + +/* register the proc file */ +static void layer7_init_proc(void) +{ + struct proc_dir_entry* entry; + entry = create_proc_entry("layer7_numpackets", 0644, proc_net); + entry->read_proc = layer7_read_proc; + entry->write_proc = layer7_write_proc; +} + +static void layer7_cleanup_proc(void) +{ + remove_proc_entry("layer7_numpackets", proc_net); +} + +static int __init ipt_layer7_init(void) +{ + layer7_init_proc(); + if(maxdatalen < 1) { + printk(KERN_WARNING "layer7: maxdatalen can't be < 1, using 1\n"); + maxdatalen = 1; + } + /* This is not a hard limit. It's just here to prevent people from + bringing their slow machines to a grinding halt. */ + else if(maxdatalen > 65536) { + printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, using 65536\n"); + maxdatalen = 65536; + } + return ipt_register_match(&layer7_match); +} + +static void __exit ipt_layer7_fini(void) +{ + layer7_cleanup_proc(); + ipt_unregister_match(&layer7_match); +} + +module_init(ipt_layer7_init); +module_exit(ipt_layer7_fini); diff --git a/net/ipv4/netfilter/ipt_time.c b/net/ipv4/netfilter/ipt_time.c new file mode 100644 index 00000000..428968b8 --- /dev/null +++ b/net/ipv4/netfilter/ipt_time.c @@ -0,0 +1,178 @@ +/* + This is a module which is used for time matching + It is using some modified code from dietlibc (localtime() function) + that you can find at http://www.fefe.de/dietlibc/ + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL + 2001-05-04 Fabrice MARIE : initial development. + 2001-21-05 Fabrice MARIE : bug fix in the match code, + thanks to "Zeng Yu" for bug report. + 2001-26-09 Fabrice MARIE : force the match to be in LOCAL_IN or PRE_ROUTING only. + 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, + added Nguyen Dang Phuoc Dong patch to support timezones. + 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO. +*/ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Fabrice MARIE "); +MODULE_DESCRIPTION("Match arrival timestamp/date"); +MODULE_LICENSE("GPL"); + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + + long int tm_gmtoff; /* we don't care, we count from GMT */ + const char *tm_zone; /* we don't care, we count from GMT */ +}; + +static void +localtime(const u32 time, struct tm *r); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct xt_match *match, + const void *matchinfo, + int offset, + unsigned int protoff, + int *hotdrop) +{ + const struct ipt_time_info *info = matchinfo; /* match info for rule */ + struct tm currenttime; /* time human readable */ + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; + u_int16_t packet_time; + + /* We might not have a timestamp, get one */ + if (skb->tstamp.off_sec == 0) + __net_timestamp((struct sk_buff *)skb); + + /* First we make sure we are in the date start-stop boundaries */ + if ((skb->tstamp.off_sec < info->date_start) || (skb->tstamp.off_sec > info->date_stop)) + return 0; /* We are outside the date boundaries */ + + /* Transform the timestamp of the packet, in a human readable form */ + localtime(skb->tstamp.off_sec, ¤ttime); + + /* check if we match this timestamp, we start by the days... */ + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) + return 0; /* the day doesn't match */ + + /* ... check the time now */ + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; + if ((packet_time < info->time_start) || (packet_time > info->time_stop)) + return 0; + + /* here we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const void *ip, + const struct xt_match *match, + void *matchinfo, + unsigned int hook_mask) +{ + struct ipt_time_info *info = matchinfo; /* match info for rule */ + + /* First, check that we are in the correct hooks */ + if (hook_mask + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + { + printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); + return 0; + } + + /* Now check the coherence of the data ... */ + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ + (info->time_stop > 1439)) + { + printk(KERN_WARNING "ipt_time: invalid argument\n"); + return 0; + } + + return 1; +} + +static struct ipt_match time_match = { + .name = "time", + .match = &match, + .matchsize = sizeof(struct ipt_time_info), + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + printk("ipt_time loading\n"); + return ipt_register_match(&time_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&time_match); + printk("ipt_time unloaded\n"); +} + +module_init(init); +module_exit(fini); + + +/* The part below is borowed and modified from dietlibc */ + +/* seconds per day */ +#define SPD 24*60*60 + +static void +localtime(const u32 time, struct tm *r) { + u32 i, timep; + extern struct timezone sys_tz; + const unsigned int __spm[12] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + }; + register u32 work; + + timep = time - (sys_tz.tz_minuteswest * 60); + work=timep%(SPD); + r->tm_sec=work%60; work/=60; + r->tm_min=work%60; r->tm_hour=work/60; + work=timep/(SPD); + r->tm_wday=(4+work)%7; + for (i=1970; ; ++i) { + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; + if (work>k) + work-=k; + else + break; + } + r->tm_year=i-1900; + for (i=11; i && __spm[i]>work; --i) ; + r->tm_mon=i; + r->tm_mday=work-__spm[i]+1; +} diff --git a/net/ipv4/netfilter/regexp/regexp.c b/net/ipv4/netfilter/regexp/regexp.c new file mode 100644 index 00000000..90069888 --- /dev/null +++ b/net/ipv4/netfilter/regexp/regexp.c @@ -0,0 +1,1197 @@ +/* + * regcomp and regexec -- regsub and regerror are elsewhere + * @(#)regexp.c 1.3 of 18 April 87 + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + * + * This code was modified by Ethan Sommer to work within the kernel + * (it now uses kmalloc etc..) + * + * Modified slightly by Matthew Strait to use more modern C. + */ + +#include "regexp.h" +#include "regmagic.h" + +/* added by ethan and matt. Lets it work in both kernel and user space. +(So iptables can use it, for instance.) Yea, it goes both ways... */ +#if __KERNEL__ + #define malloc(foo) kmalloc(foo,GFP_ATOMIC) +#else + #define printk(format,args...) printf(format,##args) +#endif + +void regerror(char * s) +{ + printk("<3>Regexp: %s\n", s); + /* NOTREACHED */ +} + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * See regmagic.h for one further detail of program structure. + */ + + +/* + * Utility definitions. + */ +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +struct match_globals { +char *reginput; /* String-input pointer. */ +char *regbol; /* Beginning of input, for ^ check. */ +char **regstartp; /* Pointer to startp array. */ +char **regendp; /* Ditto for endp. */ +char *regparse; /* Input-scan pointer. */ +int regnpar; /* () count. */ +char regdummy; +char *regcode; /* Code-emit pointer; ®dummy = don't. */ +long regsize; /* Code size. */ +}; + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg(struct match_globals *g, int paren,int *flagp); +STATIC char *regbranch(struct match_globals *g, int *flagp); +STATIC char *regpiece(struct match_globals *g, int *flagp); +STATIC char *regatom(struct match_globals *g, int *flagp); +STATIC char *regnode(struct match_globals *g, char op); +STATIC char *regnext(struct match_globals *g, char *p); +STATIC void regc(struct match_globals *g, char b); +STATIC void reginsert(struct match_globals *g, char op, char *opnd); +STATIC void regtail(struct match_globals *g, char *p, char *val); +STATIC void regoptail(struct match_globals *g, char *p, char *val); + + +__kernel_size_t my_strcspn(const char *s1,const char *s2) +{ + char *scan1; + char *scan2; + int count; + + count = 0; + for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { + for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp * +regcomp(char *exp,int *patternsize) +{ + register regexp *r; + register char *scan; + register char *longest; + register int len; + int flags; + struct match_globals g; + + /* commented out by ethan + extern char *malloc(); + */ + + if (exp == NULL) + FAIL("NULL argument"); + + /* First pass: determine size, legality. */ + g.regparse = exp; + g.regnpar = 1; + g.regsize = 0L; + g.regcode = &g.regdummy; + regc(&g, MAGIC); + if (reg(&g, 0, &flags) == NULL) + return(NULL); + + /* Small enough for pointer-storage convention? */ + if (g.regsize >= 32767L) /* Probably could be 65535L. */ + FAIL("regexp too big"); + + /* Allocate space. */ + *patternsize=sizeof(regexp) + (unsigned)g.regsize; + r = (regexp *)malloc(sizeof(regexp) + (unsigned)g.regsize); + if (r == NULL) + FAIL("out of space"); + + /* Second pass: emit code. */ + g.regparse = exp; + g.regnpar = 1; + g.regcode = r->program; + regc(&g, MAGIC); + if (reg(&g, 0, &flags) == NULL) + return(NULL); + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP(regnext(&g, scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * regmust. Resolve ties in favor of later strings, since + * the regstart check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ + if (flags&SPSTART) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = regnext(&g, scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return(r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char * +reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ ) +{ + register char *ret; + register char *br; + register char *ender; + register int parno = 0; /* 0 makes gcc happy */ + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (g->regnpar >= NSUBEXP) + FAIL("too many ()"); + parno = g->regnpar; + g->regnpar++; + ret = regnode(g, OPEN+parno); + } else + ret = NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(g, &flags); + if (br == NULL) + return(NULL); + if (ret != NULL) + regtail(g, ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + while (*g->regparse == '|') { + g->regparse++; + br = regbranch(g, &flags); + if (br == NULL) + return(NULL); + regtail(g, ret, br); /* BRANCH -> BRANCH. */ + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode(g, (paren) ? CLOSE+parno : END); + regtail(g, ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != NULL; br = regnext(g, br)) + regoptail(g, br, ender); + + /* Check for proper termination. */ + if (paren && *g->regparse++ != ')') { + FAIL("unmatched ()"); + } else if (!paren && *g->regparse != '\0') { + if (*g->regparse == ')') { + FAIL("unmatched ()"); + } else + FAIL("junk on end"); /* "Can't happen". */ + /* NOTREACHED */ + } + + return(ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char * +regbranch(struct match_globals *g, int *flagp) +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(g, BRANCH); + chain = NULL; + while (*g->regparse != '\0' && *g->regparse != '|' && *g->regparse != ')') { + latest = regpiece(g, &flags); + if (latest == NULL) + return(NULL); + *flagp |= flags&HASWIDTH; + if (chain == NULL) /* First piece. */ + *flagp |= flags&SPSTART; + else + regtail(g, chain, latest); + chain = latest; + } + if (chain == NULL) /* Loop ran zero times. */ + (void) regnode(g, NOTHING); + + return(ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static char * +regpiece(struct match_globals *g, int *flagp) +{ + register char *ret; + register char op; + register char *next; + int flags; + + ret = regatom(g, &flags); + if (ret == NULL) + return(NULL); + + op = *g->regparse; + if (!ISMULT(op)) { + *flagp = flags; + return(ret); + } + + if (!(flags&HASWIDTH) && op != '?') + FAIL("*+ operand could be empty"); + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert(g, STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert(g, BRANCH, ret); /* Either x */ + regoptail(g, ret, regnode(g, BACK)); /* and loop */ + regoptail(g, ret, ret); /* back */ + regtail(g, ret, regnode(g, BRANCH)); /* or */ + regtail(g, ret, regnode(g, NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert(g, PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(g, BRANCH); /* Either */ + regtail(g, ret, next); + regtail(g, regnode(g, BACK), ret); /* loop back */ + regtail(g, next, regnode(g, BRANCH)); /* or */ + regtail(g, ret, regnode(g, NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert(g, BRANCH, ret); /* Either x */ + regtail(g, ret, regnode(g, BRANCH)); /* or */ + next = regnode(g, NOTHING); /* null. */ + regtail(g, ret, next); + regoptail(g, ret, next); + } + g->regparse++; + if (ISMULT(*g->regparse)) + FAIL("nested *?+"); + + return(ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static char * +regatom(struct match_globals *g, int *flagp) +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*g->regparse++) { + case '^': + ret = regnode(g, BOL); + break; + case '$': + ret = regnode(g, EOL); + break; + case '.': + ret = regnode(g, ANY); + *flagp |= HASWIDTH|SIMPLE; + break; + case '[': { + register int class; + register int classend; + + if (*g->regparse == '^') { /* Complement of range. */ + ret = regnode(g, ANYBUT); + g->regparse++; + } else + ret = regnode(g, ANYOF); + if (*g->regparse == ']' || *g->regparse == '-') + regc(g, *g->regparse++); + while (*g->regparse != '\0' && *g->regparse != ']') { + if (*g->regparse == '-') { + g->regparse++; + if (*g->regparse == ']' || *g->regparse == '\0') + regc(g, '-'); + else { + class = UCHARAT(g->regparse-2)+1; + classend = UCHARAT(g->regparse); + if (class > classend+1) + FAIL("invalid [] range"); + for (; class <= classend; class++) + regc(g, class); + g->regparse++; + } + } else + regc(g, *g->regparse++); + } + regc(g, '\0'); + if (*g->regparse != ']') + FAIL("unmatched []"); + g->regparse++; + *flagp |= HASWIDTH|SIMPLE; + } + break; + case '(': + ret = reg(g, 1, &flags); + if (ret == NULL) + return(NULL); + *flagp |= flags&(HASWIDTH|SPSTART); + break; + case '\0': + case '|': + case ')': + FAIL("internal urp"); /* Supposed to be caught earlier. */ + break; + case '?': + case '+': + case '*': + FAIL("?+* follows nothing"); + break; + case '\\': + if (*g->regparse == '\0') + FAIL("trailing \\"); + ret = regnode(g, EXACTLY); + regc(g, *g->regparse++); + regc(g, '\0'); + *flagp |= HASWIDTH|SIMPLE; + break; + default: { + register int len; + register char ender; + + g->regparse--; + len = my_strcspn((const char *)g->regparse, (const char *)META); + if (len <= 0) + FAIL("internal disaster"); + ender = *(g->regparse+len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(g, EXACTLY); + while (len > 0) { + regc(g, *g->regparse++); + len--; + } + regc(g, '\0'); + } + break; + } + + return(ret); +} + +/* + - regnode - emit a node + */ +static char * /* Location. */ +regnode(struct match_globals *g, char op) +{ + register char *ret; + register char *ptr; + + ret = g->regcode; + if (ret == &g->regdummy) { + g->regsize += 3; + return(ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + g->regcode = ptr; + + return(ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc(struct match_globals *g, char b) +{ + if (g->regcode != &g->regdummy) + *g->regcode++ = b; + else + g->regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert(struct match_globals *g, char op, char* opnd) +{ + register char *src; + register char *dst; + register char *place; + + if (g->regcode == &g->regdummy) { + g->regsize += 3; + return; + } + + src = g->regcode; + g->regcode += 3; + dst = g->regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail(struct match_globals *g, char *p, char *val) +{ + register char *scan; + register char *temp; + register int offset; + + if (p == &g->regdummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(g, scan); + if (temp == NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset>>8)&0377; + *(scan+2) = offset&0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail(struct match_globals *g, char *p, char *val) +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == NULL || p == &g->regdummy || OP(p) != BRANCH) + return; + regtail(g, OPERAND(p), val); +} + +/* + * regexec and friends + */ + + +/* + * Forwards. + */ +STATIC int regtry(struct match_globals *g, regexp *prog, char *string); +STATIC int regmatch(struct match_globals *g, char *prog); +STATIC int regrepeat(struct match_globals *g, char *p); + +#ifdef DEBUG +int regnarrate = 0; +void regdump(); +STATIC char *regprop(char *op); +#endif + +/* + - regexec - match a regexp against a string + */ +int +regexec(regexp *prog, char *string) +{ + register char *s; + struct match_globals g; + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + printk("<3>Regexp: NULL parameter\n"); + return(0); + } + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + printk("<3>Regexp: corrupted program\n"); + return(0); + } + + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == NULL) /* Not present. */ + return(0); + } + + /* Mark beginning of line for ^ . */ + g.regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return(regtry(&g, prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(&g, prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(&g, prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} + +/* + - regtry - try match at specific point + */ +static int /* 0 failure, 1 success */ +regtry(struct match_globals *g, regexp *prog, char *string) +{ + register int i; + register char **sp; + register char **ep; + + g->reginput = string; + g->regstartp = prog->startp; + g->regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (regmatch(g, prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = g->reginput; + return(1); + } else + return(0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int /* 0 failure, 1 success */ +regmatch(struct match_globals *g, char *prog) +{ + register char *scan = prog; /* Current node. */ + char *next; /* Next node. */ + +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", regprop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", regprop(scan)); +#endif + next = regnext(g, scan); + + switch (OP(scan)) { + case BOL: + if (g->reginput != g->regbol) + return(0); + break; + case EOL: + if (*g->reginput != '\0') + return(0); + break; + case ANY: + if (*g->reginput == '\0') + return(0); + g->reginput++; + break; + case EXACTLY: { + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *g->reginput) + return(0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, g->reginput, len) != 0) + return(0); + g->reginput += len; + } + break; + case ANYOF: + if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) == NULL) + return(0); + g->reginput++; + break; + case ANYBUT: + if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) != NULL) + return(0); + g->reginput++; + break; + case NOTHING: + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + register int no; + register char *save; + + no = OP(scan) - OPEN; + save = g->reginput; + + if (regmatch(g, next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (g->regstartp[no] == NULL) + g->regstartp[no] = save; + return(1); + } else + return(0); + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + { + register int no; + register char *save; + + no = OP(scan) - CLOSE; + save = g->reginput; + + if (regmatch(g, next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (g->regendp[no] == NULL) + g->regendp[no] = save; + return(1); + } else + return(0); + } + break; + case BRANCH: { + register char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = g->reginput; + if (regmatch(g, OPERAND(scan))) + return(1); + g->reginput = save; + scan = regnext(g, scan); + } while (scan != NULL && OP(scan) == BRANCH); + return(0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + register char nextch; + register int no; + register char *save; + register int min; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = g->reginput; + no = regrepeat(g, OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *g->reginput == nextch) + if (regmatch(g, next)) + return(1); + /* Couldn't or didn't -- back up. */ + no--; + g->reginput = save + no; + } + return(0); + } + break; + case END: + return(1); /* Success! */ + break; + default: + printk("<3>Regexp: memory corruption\n"); + return(0); + break; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + printk("<3>Regexp: corrupted pointers\n"); + return(0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int +regrepeat(struct match_globals *g, char *p) +{ + register int count = 0; + register char *scan; + register char *opnd; + + scan = g->reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + printk("<3>Regexp: internal foulup\n"); + count = 0; /* Best compromise. */ + break; + } + g->reginput = scan; + + return(count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static char* +regnext(struct match_globals *g, char *p) +{ + register int offset; + + if (p == &g->regdummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(regexp *r) +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + /* extern char *strchr(); */ + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(char *op) +{ +#define BUFLEN 50 + register char *p; + static char buf[BUFLEN]; + + strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + printk("<3>Regexp: corrupted opcode\n"); + break; + } + if (p != NULL) + strncat(buf, p, BUFLEN-strlen(buf)); + return(buf); +} +#endif + + diff --git a/net/ipv4/netfilter/regexp/regexp.h b/net/ipv4/netfilter/regexp/regexp.h new file mode 100644 index 00000000..a72eba71 --- /dev/null +++ b/net/ipv4/netfilter/regexp/regexp.h @@ -0,0 +1,41 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ + +#ifndef REGEXP_H +#define REGEXP_H + + +/* +http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h , +which contains a version of this library, says: + + * + * NSUBEXP must be at least 10, and no greater than 117 or the parser + * will not work properly. + * + +However, it looks rather like this library is limited to 10. If you think +otherwise, let us know. +*/ + +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +regexp * regcomp(char *exp, int *patternsize); +int regexec(regexp *prog, char *string); +void regsub(regexp *prog, char *source, char *dest); +void regerror(char *s); + +#endif diff --git a/net/ipv4/netfilter/regexp/regmagic.h b/net/ipv4/netfilter/regexp/regmagic.h new file mode 100644 index 00000000..5acf4478 --- /dev/null +++ b/net/ipv4/netfilter/regexp/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/net/ipv4/netfilter/regexp/regsub.c b/net/ipv4/netfilter/regexp/regsub.c new file mode 100644 index 00000000..339631f0 --- /dev/null +++ b/net/ipv4/netfilter/regexp/regsub.c @@ -0,0 +1,95 @@ +/* + * regsub + * @(#)regsub.c 1.3 of 2 April 86 + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * + * This code was modified by Ethan Sommer to work within the kernel + * (it now uses kmalloc etc..) + * + */ +#include "regexp.h" +#include "regmagic.h" +#include + + +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#if 0 +//void regerror(char * s) +//{ +// printk("regexp(3): %s", s); +// /* NOTREACHED */ +//} +#endif + +/* + - regsub - perform substitutions after a regexp match + */ +void +regsub(regexp * prog, char * source, char * dest) +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + + /* Not necessary and gcc doesn't like it -MLS */ + /*extern char *strncpy();*/ + + if (prog == NULL || source == NULL || dest == NULL) { + regerror("NULL parm to regsub"); + return; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub"); + return; + } + + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { + len = prog->endp[no] - prog->startp[no]; + (void) strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ + regerror("damaged match string"); + return; + } + } + } + *dst++ = '\0'; +} diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9e1bd374..79939522 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -108,11 +108,14 @@ #include #include #include +#include /* * Snmp MIB for the UDP layer */ +static xfrm4_rcv_encap_t xfrm4_rcv_encap_func; + DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly; struct hlist_head udp_hash[UDP_HTABLE_SIZE]; @@ -917,6 +920,42 @@ static void udp_close(struct sock *sk, long timeout) sk_common_release(sk); } +#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) + +/* if XFRM isn't a module, then register it directly. */ +#if 0 && !defined(CONFIG_XFRM_MODULE) && !defined(CONFIG_IPSEC_NAT_TRAVERSAL) +static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = xfrm4_rcv_encap; +#else +static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL; +#endif + +int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func + , xfrm4_rcv_encap_t *oldfunc) +{ + if(oldfunc != NULL) { + *oldfunc = xfrm4_rcv_encap_func; + } + +#if 0 + if(xfrm4_rcv_encap_func != NULL) + return -1; +#endif + + xfrm4_rcv_encap_func = func; + return 0; +} + +int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func) +{ + if(xfrm4_rcv_encap_func != func) + return -1; + + xfrm4_rcv_encap_func = NULL; + return 0; +} +#endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */ + + /* return: * 1 if the the UDP system should process it * 0 if we should drop this packet @@ -924,9 +963,9 @@ static void udp_close(struct sock *sk, long timeout) */ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) { -#ifndef CONFIG_XFRM +#if !defined(CONFIG_XFRM) && !defined(CONFIG_IPSEC_NAT_TRAVERSAL) return 1; -#else +#else /* either CONFIG_XFRM or CONFIG_IPSEC_NAT_TRAVERSAL */ struct udp_sock *up = udp_sk(sk); struct udphdr *uh; struct iphdr *iph; @@ -943,7 +982,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) /* if this is not encapsulated socket, then just return now */ if (!encap_type) - return 1; + return 3; /* If this is a paged skb, make sure we pull up * whatever data we need to look at. */ @@ -966,7 +1005,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) len = sizeof(struct udphdr); } else /* Must be an IKE packet.. pass it through */ - return 1; + return 4; break; case UDP_ENCAP_ESPINUDP_NON_IKE: /* Check if this is a keepalive packet. If so, eat it. */ @@ -979,7 +1018,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) len = sizeof(struct udphdr) + 2 * sizeof(u32); } else /* Must be an IKE packet.. pass it through */ - return 1; + return 5; break; } @@ -990,6 +1029,8 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) */ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return 0; + if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return 0; /* Now we can update and verify the packet length... */ iph = skb->nh.iph; @@ -1055,9 +1096,13 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) return 0; } if (ret < 0) { - /* process the ESP packet */ - ret = xfrm4_rcv_encap(skb, up->encap_type); - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + if(xfrm4_rcv_encap_func != NULL) { + ret = (*xfrm4_rcv_encap_func)(skb, up->encap_type); + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + } else { + UDP_INC_STATS_BH(UDP_MIB_INERRORS); + ret = 1; + } return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ @@ -1639,3 +1684,9 @@ EXPORT_SYMBOL(udp_poll); EXPORT_SYMBOL(udp_proc_register); EXPORT_SYMBOL(udp_proc_unregister); #endif + +#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) +EXPORT_SYMBOL(udp4_register_esp_rcvencap); +EXPORT_SYMBOL(udp4_unregister_esp_rcvencap); +#endif + diff --git a/net/llc/Kconfig b/net/llc/Kconfig index b91c6510..11005f8f 100644 --- a/net/llc/Kconfig +++ b/net/llc/Kconfig @@ -1,5 +1,5 @@ config LLC - tristate + tristate "LLC support" depends on NET config LLC2 diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 1e5207b8..e23fcc66 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -408,7 +408,8 @@ __build_packet_message(struct nfulnl_instance *inst, const struct net_device *indev, const struct net_device *outdev, const struct nf_loginfo *li, - const char *prefix) + const char *prefix, + unsigned int prefix_len) { unsigned char *old_tail; struct nfulnl_msg_packet_hdr pmsg; @@ -432,12 +433,8 @@ __build_packet_message(struct nfulnl_instance *inst, NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); - if (prefix) { - int slen = strlen(prefix); - if (slen > NFULNL_PREFIXLEN) - slen = NFULNL_PREFIXLEN; - NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix); - } + if (prefix) + NFA_PUT(inst->skb, NFULA_PREFIX, prefix_len, prefix); if (indev) { tmp_uint = htonl(indev->ifindex); @@ -598,7 +595,7 @@ nfulnl_log_packet(unsigned int pf, const struct nf_loginfo *li_user, const char *prefix) { - unsigned int size, data_len; + unsigned int size, data_len, prefix_len; struct nfulnl_instance *inst; const struct nf_loginfo *li; unsigned int qthreshold; @@ -632,10 +629,15 @@ nfulnl_log_packet(unsigned int pf, #endif + NFA_SPACE(sizeof(u_int32_t)) /* mark */ + NFA_SPACE(sizeof(u_int32_t)) /* uid */ - + NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */ + NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw)) + NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp)); + if (prefix) { + prefix_len = strlen(prefix) + 1; + size += NFA_SPACE(prefix_len); + } else + prefix_len = 0; + UDEBUG("initial size=%u\n", size); spin_lock_bh(&inst->lock); @@ -703,7 +705,7 @@ nfulnl_log_packet(unsigned int pf, inst->qlen++; __build_packet_message(inst, skb, data_len, pf, - hooknum, in, out, li, prefix); + hooknum, in, out, li, prefix, prefix_len); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index e52afab4..2320451c 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -238,7 +238,9 @@ int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) { struct sockaddr_in sin = { .sin_family = AF_INET, +#if 0 // mask by Victor Yu. 02-12-2007 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), +#endif }; struct portmap_args map = { .pm_prog = prog, @@ -254,6 +256,9 @@ int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) struct rpc_clnt *pmap_clnt; int error = 0; +#if 1 // add by Victor Yu. 02-12-2007 + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n", prog, vers, prot, port); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 757fc91e..9d6cfc8a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -608,14 +608,18 @@ static inline size_t xs_tcp_copy_data(skb_reader_t *desc, void *p, size_t len) if (len > desc->count) len = desc->count; if (skb_copy_bits(desc->skb, desc->offset, p, len)) { +#if 0 // mask by Victor Yu. 03-03-2007 dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", len, desc->count); +#endif return 0; } desc->offset += len; desc->count -= len; +#if 0 // mask by Victor Yu. 03-03-2007 dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", len, desc->count); +#endif return len; } diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index f0ff248f..c62d811e 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -23,7 +23,8 @@ quiet_cmd_modules_install = INSTALL $@ INSTALL_MOD_DIR ?= extra ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(KBUILD_EXTMOD),,$(@D)) -modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D)) +#modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D)) +modinst_dir = $(subst $(dir $(TOPDIR))modules/,,$(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))) $(modules): $(call cmd,modules_install,$(MODLIB)/$(modinst_dir)) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 65e0a79c..13cff3eb 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -68,7 +68,7 @@ quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules PHONY += __modpost __modpost: $(modules:.ko=.o) FORCE - $(call cmd,modpost) + -$(call cmd,modpost) quiet_cmd_kernel-mod = MODPOST $@ cmd_kernel-mod = $(cmd_modpost) diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 8a287568..bd2981b7 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "modpost.h" /* diff --git a/usr/Makefile b/usr/Makefile index 382702ad..5b31c0b6 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -3,8 +3,6 @@ # klibcdirs:; -PHONY += klibcdirs - # Generate builtin.o based on initramfs_data.o obj-y := initramfs_data.o @@ -20,7 +18,7 @@ $(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE hostprogs-y := gen_init_cpio initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ - $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) + $(CONFIG_INITRAMFS_SOURCE),-d) ramfs-args := \ $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \ $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) -- 2.11.4.GIT

1}1=i9=%hCI9&9-sIO}n{{NikfPUq1 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%0D~f}wu=3g^{W zJ6sF5VC~eS9|zD61%7;%5`SvQvhDfN#20&Y{%Dqda&x6l+g*QFEae}9zVfh@T8%mF z_P!_kk%@d|+znlP3cR|E?51TW^1)aOcqH05M-AoB2?>qcDC>fD*Rut`x5&78Z@QJv z=l)EOgMMDV?P`qhmFK-_X8lm!4VyJrYYovc%KXF!(n<26IoW%}e~06e99&B0)%0Px zll~tqTnC!w?Z?`?KJJRYR%7{IUtGhOe1Y`iEa>2)%3wGL@>{K)&TAjr1^Ew|F?^cv zOQ!Py=b&d}{C@_S--pF~k%>TaDzsgdzB_Y?lZnlqUzdb?IDc_c!<~3>_Q|53ORtXW z>iy(tr_4iZX&!v~%{p^Yr#-@cOe4K9Ie&@wwsQky8Mjc`kjV|x$(yIRl9vF_l14F4 za2T>A>#1`LVcCmFi@llW)i|&A`Kzmq{|wNIau`qA1sc2`M; z|J>jZt$2UX#GZwNG`9R)oe@N<1sF3N}0T3 z$r@j+W1-L<;YB;Nif{0IUo^JK^?h}v)}1LM(^s|Bst`-r#}j4)GsNkLXP8H6`cur%5~Sxp6p&%vZ2j# zX#)gpzb4ca%m)LDnSV{_>bP0Kd?-L1a;s{M|Ko0{1HMG;BsX%-PiWfm6Q$=HYq7G? zYOloqV1<V_+jh!$ooEz_s--xbQqIdCG$DF?|3D)cEgMY_XheM%y_IYr5QZc=H5b;_^1cWI%4gj+El0PV+YjI z+=U~?AK*7JPVVmue)@6Q&68bzhxDIw!e=XmubbRVvxoBkg64&0P0j?0siZjUj&+b1e`c(Kr%s#{e@5EH=9TS_i9ASIBBS@n zwxJ&?MR`N=uUEtp+!wrpGEc=>%Ea!ejKqe01UzNB)g?Th*LGNgvfs^f?uGm-e>-|^ z>Bng&SLbcuj-6VY?`ztdW33$ajd3pDX8#g8Cz$xXgI43Y;2$7Mo((+{`o&YE#r__N z=m1&Zqzl>K_|kAMlJ-5>bBC;BWji9id`dj^M&}vtq@mkv-^y+{5M?eTQ~ycJ$LMO^ZL5x|X${Dtw-#{m_>c{B`wSqZ8=& z&)4sl#f(*z^~-WQ4vc4fw&<&RUe1uVuPr=7Slb%b91mkH{rCPIbHsUOf1VWGf_ijj z0)2?-&q+Mc@@|5A>bYPtBl%cKW4A$viAg-Ks`xH-fvnEQP1%g~kyL!6XZVRc>&s`f zh0qt7es15C_e7ShbBxUWx|y$|X1?e%5>-RKXkTqOe#Gdk!>+fP>ms{l=y(6gd@Ln- zpusnn=4eA2o7DM0rnjusawTLu>c+o3ep1#qV>0;r0DcEDcjj69g?`7pM|tk{!IL6; zhYgRW?S(PmqX3&vRcl}AuVQUdKcF4tD{`K8$7_7JlkIT)zZyR%w!<4CbMl>=@Z7~J z4%s8=^8OFTGlrUVJeP_MsXT`!=YV$PZ3*b*_|D3iL$dG9I9~ugZvphY1(SQdZ@+$Q z;4}Y5yJh9JvKl)X9hCMRvg!$uK{OXsn!Ag z{gkc9uhmBa=TZDWQFhJ2!Fc1;>&HrVPx71P&^za%t$EOywi){>_cR9npk)r$ zRgN0o+X)%|_a=`T^W-r0`0aF@>1BTDjC=QWl;m-(KRkY1`@Noss)0tO?YDbzKDn%4 zlgvK(R{)pymg$ERF^ROn-i+TJIBr);@;7nLlECF<#$Rk#Kn>8o``dH1O_%mvv3oh~ zCeBjZ)qQ*VigSl*&E6DH1A3209r5kme(bR5JDC4qM#tzd4<7xSIR9+F$8HP8RAn^i z%vH55y4Evz&JNJ;hr6MJkG9gM!~l;T5d)kA-qZrufBxFwKp*5%1-Wgfvn#i=;U(Hy zbFmC`ypFW@puHyZ?qkps4|*x5wGhO4BhEwkFLh*~ zAI2T#?OX+!TjvzzJ{@CE#l~*Qx?~Q8{NniAo~_pk0A9_}qXCtN$V?n28nP(xNJUrd#%CtdDkFS>b{u+<1lhqWzlbg>}3B<75Hbx*8ij)tYuPN${kBWhpgniz(AmOI*)BIvAC zNxLo5?X*Sc6YtXkKbD;Ijr5>4u~}+*MpE2!Y{$9l_j*|SXfdb%W^az{nXeaL2?gD^(z+~9-#X60 zl_p+zG#Y9>{XTFQN4?_LNWQwisOxjiV0@#w9#A@G#NR9&iZ4pxeso`1 ztlB$#zpw23;j-`hZQo$p_S+QueirlTLe`AyIAP{TjV5}8?+?i~3k$xCLqF`JD}PiQ zR+6iMwri>Jr&13bBFy=%vA#{8YYcoI=TXW%N?ldOI1bvdmGgr`#J$%A-a4O+#CX&F?1SMQ6pdFL(Exg|<8FFx4wT5?pM?P>0IxUHaFV5zOrA( zF|6vJnO&D>4G;26$Q={nPFGD&qBjzB+|Zs2(?YxW{V&~hTyP$Iwc_%hr}JUF_p$## zTkc)?PmaTHe3R>kdRf>>=Uu$}`ladozQt+pm4>u8yE*O6YfO6`yV70{{vSS+_TJ#{ z(SCeR+FKG|Q-g8U@|)I{<2nyDWU;YZj>|rO$4%4JOdy}+j(JJ@3M`3t$b4J0abrwN zq?T5vw-xQ~3w3&fJ;zJ?`^S6C{yx^?k~ry!I`|23%PIOaR0oG=wz@yu4>%vRvUM)cu)JiDOmej4}J z;eHzTJ1H;W{;g&A83#rmh~>E7h5M6m|F*LG^KgHO*>Bl|`)A_*{6Lqt1#>V*=^VSd zcFfzyvXj0ne;G0n`o9y$lQ>?%q1*=L__kWmiDaVJ8~dBVf$v+LqW3cgba_7a1xK}C za>&r~ad@^u=Vm?peWx?G`0PxfVMHyb2kf-y&7t3DpA|kUb;Hazs}r3PhejOzk5}kF z-|5vPbO|nZKeP%2$3UQ}BJ*X{)SIx&|KG2-ar`7q2Z!YzyUOuKyqZ z?QUs5|B8;|kr)DF0}!5ye$ZY-nVPiRCU<)_ z_}@cVGxV>aebH%Z^Wxb}-a_V~wA-McAL!?p@Xh`um$iAza9H-L!puk8@ciz6=J?z0 zbP2zS8hnaChB_6e+hje=JG#lE4{^2W`zZ5{?+dF^x{eaB-HZOxjw61qsp+Z~Yp)px z*X4Xyught8n6=)xKIlWs`fs1Y(ed|_)I$9CX>GOfTbW?i;lv6x&`FwzdGqt+mFm$u z8zrWUwPU)i&IoB`HS~${b**Gw>$OSwt{Oam_nFTjkkU53uo|B4j(i)s>JhG0*3(`t z`)l3atz*@|I?U%MlOL6M9Mz)Vr|s$1CSCiEeW71N*y+|XG-QFG!09Tio2#l8lK!II z?e_Dz`M{_0oI-&abMsT83v&(IB)`uk73lZRVjAz~nm)cbK>OQ%p(CXCALO^z_j*4} zbc)RQe)Da73$VJXD&7QsiX*;I+Y~u=->2E9dDkV~s@V(EHF&0Gx*E!jPgqM0j49M} zRuztNP0Zq&*yS-tQ~CYqi2KZ=+8juGJ5)ONLtE3&k@=GzaCGeq(qq;c*ZR^s#2+WM zt@0lS484Oq90fiRw+2HRzeI*iXq!>r|Hs_h$47OR`NQ|TBn)8+CnRap7~2yPG1llF zTB@<44lP<#_UAw;#md&PrM9~dk4Bf(y36X2Hz=EQ10=jX(9GJpi~Zp~SkWK$sqVC; z-TwM%H7(FL0nf~E3{7f_TKf_T^L)S8eV@!^cq#hZ=jD&{nVB=^+%MOC-Pe7+U)I4) zwVeA4MYkL-q5BcQfIK4oz$M?b*~|R@tEYVXy!Z{&hRt5(`=nKTKWyF?x(_~6aEkmp z@UpAl#>v#g^mPH%ko`iY?<>*wZs*yIkx|9| zZEBg1!`ip!Yx`lU>SH`xScA*RwL!)uE1jDXARQrXC7q#<0p#$JzmDlzTVKN`b3O9h zXv_|BE!4*94bvzq1XJK$kZH{N?fy6*rDGc;kw?yPqzs+tVXOcFR z2fmRjrb9|(?~S4}3e4I#9E!PBI8OsX!*luknfQ0aSQk!@fo=a`MCUFi{oG^Dv5-my zv}}{g?XkPE8?7MEEWqxTtnk3GROOdrZiw&uXZvZe#&f^P=PT%&o#PpODxY`!yM_us|IYo+Lz&sL`sk}H zy8hM%(uzg7SVLc#~ae)Wi2ExBCYe&eL@dzQex(_?$b$Iq|zBA1i){1CjR z=n%9mLTJj3Ckr&imtUyEAU&}qhC{>OIlf(L$rRV2^=TS?m1ON=dhhL4{TVx@eOLT` zVugOH=tIx8Tb=Em(KXfidU`$>WKB6=Ze;%HZ=D(&-Rm645Z7kld?Kxpy?KV@3jtOK84?}@i%y(U71F8DAVZs8D^M&C1~g% zbBQuGhdPdr{B~^QYP3z?#(I$}`b96U><%w%b$Wk`|M=Y1=(m=qXV6wgN1C}E^k??0 zt&+2Te#2HTHfyWUP1dJnKV__u4R`?tHT8CHO^fQ4I0EWC8DA^$w(%E+!`L7F>8)O~ z+nZ&K;d>G)h#uTHVS< zT=-to<81ZTqD}J5Av+*=L|$Ug+~bPZH0T z==G`r<6SS0jWYL)ZEuwr>eg9zV(ssgvtj=64d5a4eJw+3*^9RODDZLtaHt2@?L{_4 zpI2T5e0n=$;>Q&Itx{FDlD}ve@MeE$!1L|w<9LJzsEW#`3izgN2b=)x1DW0<*|P2-YcFOuP^+-6}r~#x$+s1pQGKS zIIjV9408=`%n;nb9Ma@-7G~z8yUr6gwin?>R}pS>)i4j;TC`b=8y5?19GZX|e3tfl z;E1$A`GGd_wdBhT9TdJB{HcEyQwI_={^r787Uz3*64|{{+e)wLsv^BTWm3_5VLcK~ z=XhPOg!tG_jLFt|Pd~Qx=IqyAofz8+UcSPneiZ91@x==nBO(3|+fHx$`l7b4pU`%h zb+db8N!#=(;d>$HR#)QV@SS~?IUR04e$!WKvi%Hbi7PpD{hBkR;SmEfUr$)9GoU<5 zSTH8o*8y%fI==^;{Ssd=O+6wyt#1Oh)oBf<3eLrv>oVpKe5%Z)Tw;KiWePC*QntBd z9$zMm(uC2W2{1|!Mpox|eD?XksIsK(&z%WI>4`AfV;{;8M#XadWc!fU$U1bh0JjFh zZIQOG8ebV-*D}fQUO@vp%36#y4ODz1=U`mrfL&QLdETyUY3^l?gZhI#&XbwlGY@3; ze&~SEfCsE6GpsEUJVU-_#c|>L{dkAG9rIs=3~vy2`i_R}zN6HK1)Ys9zXzQkP57Lq zDsusA?({L7)x4*id$JSbIa8Sj(6;Zt{Y%ylQkoYeK1@>|c6(+5n&C1+;F&(lu&bkA?Fubo0Y z&pyaa{O@RGe$+N{*E_Yb;Vf>ormntG}>+sQW?N*EsvUqxt-}?PW%gHJU!~ z(lySI*g|A}jHQ!j(`cVLt2IyeC}Tp+IYL`B>udh1vEY~T7{2?l9iROmWVeyA(I4MW zzDDaANejYuzZWrQ<^^URXeUb>ZY$P=`RoFcUx_~GDe>W_9dc(tjeY=hu=Z%9is7m^ zYd?auXYK1+6GwS)K-=L03GjsAfo$~I%6hT!&eQx!%CWzSedevUPOlbMHJ*>)Gm7hz zZTqC&EMrlw!S|<6Furs^_M`>6UiP;3IsZYPxe*2=9?oB%wQ?ruSlFoXXZPVp`qWbd zyKmw6E6Es}p^ACxm&4Gwe72rtTe-^cjqpRAm2@5l)~ zwr`oSDOJeN_@x{2<956cVO{GJomn5I9$?C``mm;>zOOU>V$qmCgYR=N<~bPi9E>@M zF@L0Jy?y%gdGznM%{|S0Ya9dl><4InF#VLHQ84xaABX1^_4OBxtlKpx^_gnX*RAO5 zlKZv4QMJ(v`0ZeVL8;8|3WybcEDDY(D>wG@#+kZGIaX+y(<`&XA&Pi#l<2+lQDB7?hYLiDhR+);6 zkHNqHKJVwRJZJ1rllWQa`rmwS5o2H_E-V$eq~zUYv-(ZUbs=8@ZG?Uf$fJuj9H*$F zoSCun&6&A47n54o-8DPo{WXO5Dzo=|9ymg{Cg@kYSmr3TXlNx9@lzoFUY`@&zv`-qsLrxU zvd&3?3(uv%gmndPvm`HTMEoM1mparKtM9KT>$C>z6z}s)9_PY38Gmg()`6mRx?Zmn z-n(*4pEm;2RH`bFV*I07x5`wY+U^QsY?ClHe6~+gNt}7H9bP0s-5&O23~P#Ym`pzs z?c*eSjBSLmcHiULCF9xG#4mWM1JK%k2wT7UX?v%^eFU6?mrfGda{#LhtwdYj+^l*?3+5( zYTBuADZ9s8_E49%>12L%d4rB)px(Iit233+9g7`_zFyVoO`4}u%e3v+>dvwTXvFT3 zm^J2d;+_k~b&mgP`VSILHfb>U_y(~-W-GGVmQo$>#(B;-rS2@>jTZ53L#K={U9!lY z#eJF@@Mbk=f7k_h=7xV>ljT{qZ0=^jRG)i|hJLYTc)jemg|b&jM+4e_awKdQ^c4|D z$CS}Gg5&gc{XZv;3!NdIUCX^Eu`9IAZUek(4ZQe#E#QA3qkT*Wzi_f}7D%0Sv~hFH ztztZEg~1Kc&tu=yJ|Mn`2@^N!Z1J#PGt7^}+;qnwH~P4B1Y`W2jlLaSuSC~-*#drh zi#N~S;Z5&zbJQtGtxE9OA!8q9eBz@Re|36?w`}2dFW&d*tY3qTG^ExdZw;Q_(3Wy@ zpYS4W;l8pB|NTcpYs%PO5zj_?LzvUovIgV$zGCc`zDM5`(tXwj z^nHtQmqq{mH~eR%x?~O5*A+^~Pi#<94<{FicV>lN(U&DbeAK=%7~5r9Mp&B#y~>5k zwBG79L(|)pt|c#YS>4EZr4aa?vQ`}q^IhOAX)pHhWr10= zAB#U&HUODAV6DcU=osd6^rho-Z{+h=3D3}%%K15s65_X`;YYuPu;^1Z3Y@{)T*m)I z4wL&DPeDiODk!JWFB0c}d7{HA=XrxZt1(v60*koVW@3N){9NUWa}~~~uwT}AtOGIK z>=W`dgjodrNjsc_y>U3=tih+A17XW&UgsPv?&*GyeffL32K`Nn(YDq_`BQAR=esuB z!xPu$U1nSX>zZsi;1*#`J%MjW5q#&$e*$9_;~8=v;p(p)pObYFm?tOXt9JQ=Tc2+#TTF#H%`O_Q+y zW#0}6pFw@Bzh{HOvke$LQ`=}``xe*2)_E@Z4rvklt4R53`U>`kX;?t*^zQ~jDZ1Qm`iT>V0n;&7SOuax`*S28|Bj#z@jW()H z?h^7K{&N=QNF0i!JF_~UqVDr5Jg@ue7afS-*R8IOxtaKWfey8>AM6{EhhwxWukp5A zO8K~utAOn?Mre`bw$T10wZ$=iz?EqaYdSAHc}nX;xL)~KG}}@ia9t(!=Bwsloxh3p zDckrsBC*yn(tC^vIMVaBrtPfDw=A&9i?>}Xeg_&4`U-fU3blzuFEx$_ed9WnKbpN) zuXKJ=@;J0NQE1JJgQ~mjWz|6msei6w&?^4d+rhQ~7=D($8tt0$i zZmr!Z^9Nrw3w(RSnk!g$ro+JCdVxW`p(Dhz9<*^S=317Z4Pps-jr)9`qhwsi5Bw7Q zWz&G|()Y#J-R*Xs0xescEuRINCp5Iv>%n<4`xVBdEn%$W1LQeKXJ5M{KYBCzO&XlT z`IR|tMYFE)tCE^?=G>$Wby=Wq0({C0e4;*l46eLxU~?S2ezm3jwCKZNnfH{b1IjkT z?t0m4jF05G$aoN6&SE}(-Ve$B)!8WKc1P&X0wsY3ip#gYxU>Q zW^@_MQO11;nK$x%z@eV=!dfwB8S|;EdnGS18|A8?7yXp@UtBM7q||frOlmrjA3c}8 zqF5Jp+sitB%jf?V|N7MEvbj39)2}fn=9&5DOY$Rr%q;cXjmOAO^!c%oBlRV6r@uFY zj8Pbm`;_>R5c|GZ_#er4QlaZclV36GXkuD*TN>_KF4TL4@uKv{0bW!wuL*7299Pun z9wXq>CC?1@gOc^)e<`uMQ@*N?ulJmomPc)_hvwFDA)E|F&4@{QgWccai6 z@*|WfUORbWG-mQs#GJvJW}7;_jWt307K`URd4J}sq24~0KH$xD56JuEYa)36=t-^b zBQ9;h82WIrmc_24IzH4fbn;BKIezfZr`P6q>BNb1*5-J3U!gWf5BOuPdnwQc=I49r zk7JVa*{@g5IGM&jgJw)U15S`;)c!d%!&zU0an$%aRLJEO{&&h>x0^9X;u~ciPvQS@ z`f{z-qf(zp-~_gZ_t7{1_|Exp14{cB{>MmObom9?b$c%e?YZ%E+S9h#4JUWH5ofc| z9`Y?~i)c@zZF7P4tohSv&%c+@9$zmlHMbxuGM2)LYx+|T7>C=sya=vxfoGT3q;w47 zp8`+Hw^l;yZ@9k4UjsZ%JzCnqn*Ib>t`Jxb6v48~V_v>VhBn1j*Gr^L9~IiPO@$JV!M;^y@6xT6aui<(V*W0+l=}q2><`$PZU?>~WuQm+&_Lcb` zbo2A~a=)P?)9_9v(6Zu7|;3}zLV_oesR1gj`dno zn-cJ5JVA@C>yx+9mT&BaeVAK+a)**r?%s4Ig~{I3FA^G^!u(wiW4Q0?E_IdB+gzy6bUnkMHnO z80$QY^L8`N+P+@#k>uFsoMW6lzoZ?wm;U9MEondBYp-{2TGzNuS-mfvI*BpIuV+3K z@zGK8scTD$Z?YNpm(kW8#XfeRfy@&^zpt{n^vTgQPVBqHq2r(l)F&spUH(UzDG(pX z>YR^DO#5!`f~)f)Pp?Y8SNZ!!bnwR3%Y1d%Z&~h>5MXexu_>^Bz)0xr3^^OL>@G5@ zt;b*;XRe(%^8?fcox|dbRv~iP4llu60@M?f(5%wj(PumVs|{_dE}?CAg_X!yoYP9o zXQ#-ud`*wH( zm>+FVq|p&PW3{o?I&e7ll(#dz&5J-r=ALi8oOQppOMGC2G97Rca|=bZt*N4owwvU2 zF7`|n^`6wJ)2AkU^PtChlXu|ULu%suIp3qR20ih=A)kAOXO=TwMR;G*^6PR5!5PNX z92ll9^ly~bzc(3~!arxPjHprZIZ}6eE9@QK9pvSd_7P+51lC%p&^Da9mClgle8Rjo zVqP5|5naZ@(`p}A8(V+%I6tV*b+-F@NQn-hRq5C(#{Lne0teaOo4lB_P3jTS)}rUQ zeH;#yGtUPO5}%=TjhbROOgRf2{=mHGj)ucZXa9tG{;7NDXCaMu?-KYdm0YRRRg#WH zFy_g>CCvc5ogI?HQYAaY2bJd;@$?Q{e`=qg(vmyb&v_O|C*Aw)C)r=_hjtS9x7rOm zJ-Qa2sSin6l>3)w&3sGeXsQ6N?{N-hNNcE5wDJC)D-J@g8jzS$${KqvKbUE@beu|= z(7}ZQNB^8iU>tj?N48zGW6`ctMc;+e+GilzI0RQ! zW%ZnOKBJKHnD>V8h>v;yfH~*Qy;J7iJfq*AsdVksX@FzHOK}8;JMK^c&4<+W?wh`S7q= ziz&E#+QoI=UgXOqyljGJEoerJbWv&CPDdUgX~R>1=Id!8yH`?UOEf z*e{m&xjf@3$#wh;Xy86Cj8DpMjDHB?cR4;o_?(2#Fg{r)g?Y+;0(wUO;W_lPi+5ta zl-mY8-S;(Iqmlcap$zHjRHb9m7*D(Rz$I$lL4EDR_aR(|a2><-8m_4MujydnIS1Dq zT%y<4y3Y}Qr|)CE`Odt|7n|?&PrcB5xA9$S9yrNt6Ta`pm>3Jxg6|iY`^`o79Y^BB z<=xpL$LjC&F%6jS5%YYAwLYCka;%RNQc0KcatP~y_1-4`E0K%0Q6G-~9sv#BPZ?>i z=*G1ycl;k_iYz_fkKeWn@xM4%ABY&7V*Qz>BAlYXUC7{7xCkc$hA$(|%pWS$)GBWO zE9cSv?PqAe`Yi4Hc0ti0*#i>yPkkZzK?^XQqW8eITHFgpt8{#g#WV9~$Lt09k?O>N zSDPeFUy`d6o@mf3r~Hs&UN1ja*NybQyUMo>5YKRC<*s;1=e#pHu5_H_aedBDqRk!8 zNUko)&82g7k?#y7Hf4`O?x;=CM%d*g)Mk$~hcbuAU@61LCb3@o;3jK$K-AwD2+{Sw3W(Nr#m z&sxY}ZNn!=nUB%Xk1}QQX;G)feHX-ki}5VaNYMGJ&!K%K@o6TuRcYI;UaJj|?+a^H z{9i5p>o2nDlE#)1H!wHWVUQfgZT((tioPXPIhB;XmYuIQ9xG3TTtBv-vf~@Wnudmi z=Nt4s{_C+(+Ain4+^A}mA&aY2u`A+<(AdmU*txflP%;V1* zARKGdaWkP*dnVczbSbZpKP@*n&3WEEtoJRTQyH(xTIPS^kX6+Fh4`N} zLO%F5YvgKMj@amNk9=--nKHb9s(AiH(R%pt2Z@5roh;J-93MV8>ia1~tbsH`T)P>QV3eXe(Ll&y9I3R^8cWj_Q1@jO*%;_j}W{@8~wI zUt2^Q?NyEXERr}Z+I0W=$f*(Zo2`KSN&3%Reh%rswb9#?FW7{m#@Cc*J9LKs-=80+FU%oBn1av6SvTmd{)_y`zF%E39*ZFMeOtGANzwYW(N>NB`aV{O%emC0 zo}GU0A9#tp4e5PQpQ{xj)8V-x@d@biZ#-7EKf+}r#|k5+@ZX#*TZ-I z?qj-7|73$r@z2Z-!qNP~ z-^l%^+e-e0GzPf%O8%wg{F0j~+Xce5JMwOCjO30G^wpw}8;uI~-r zJ&lcS1;Q6Z8q@M9WWBn2^5M3r5o7OX-Nm|P#@~*91FWeVOoLuPmgN~xFFq;a ztBEm?XV$-Y-c;K|IQw-SDB6LUtGm|xFa9&+y-hvMfV1Dk?h5ZX(qyg9(qD$>J9w=Z zi{a}CUhDnvU|#14<-N7QwIuP4uy(0SUhg$F0glZxT=GSE))Rk-FkB|KrLesqtBk)n z&l4Npry4(WOYT>(_Etotw-e80{}Y${44+4x4gHnpCwF*3^04VGl5g0ydWA2Ev~8~e ztq)L6yLMV3C+q9K(td=5=R9kN*k+h7*0yv_0NM>$JB9n2KFsuOu1O#CE_4ri)v<$~ z6$hV8S{d(ssT${YZM@g}i;#{R!r1SV_73YjDf~VpdsVkXUupD_`^<&;@w!EP2mGk` zTz%off{$n33S{X|Pk8D&RNKXGhp?-5nIrus!fhSbvDw)u{xKfwIF@wJe#*N7i4+h9FG+Oq0x>OFOA zMYF+U;w+z|9n4d^h`Fi9dv|GJ{9{C{fVJgo4{mhv{xi40g<(j_Vtm(i}y+?fg;d{7_ zRv-FYuVn-E&VEPVMjwBd&5y3i7x*#G?OgLZW$@sg+9u3z%4*)s=RE@z%nJtG28@Ls z;+!mBb7Cam#IpC4kq)}l2WL}icjj%3ZAj^7cHMkpMAnhCo%~dV=(yMMzmLfKbF=r< zaQ(TC9oc`e^!wWH^Jm9i!u#WPCeZEM=j!}aD%mfz`};4CjV@h3=q+s+^fZ0Kc^}{E zF$O8ZTv5Q|nT$tpwtD5}3=uy%7yH;@?egstc!_2BZR38F`9v!Ry^uY_ZNl#m<3%Au z@pm(R^K9q$?_M#(o$(=_gCUo7>O=PC;gGe)6}!0I{&!n!#` zd>JBG&oKI@Z)KCMc@Y`whl|I$4P#v=V~v1s;#ie^Q#O=dC*#ckxBRoYllWzLB7f|_ z^Q)*sQmGE_J6MOvTpcUN^Jum3(mTXg{o8qM+hrT!BAd6wp9RUc9rQY8CEc*SA2jHo zM;(yx8UeNL!1O`yK#;It9BiM*m=K;<;BT&KPwvhHlBp2;C9Yo2eiHioB7SdU?AQ&s zmQ+$#;>$NT<_qypH{|K7u47DshQ9FrwxinboA>-@2XJp(t^>_lig#P5o3UXXUQnhk zEa2IxQdP@UD#X3A=bI-amhNftE;1KQqnU4+xlwFqoyQo#L}FdG9^Xli$!|2{JM->Q zmRV-417En#3)qXY(NwpGJ#u4{;qP$xRJ4GuaL+_V2m5r!oR1YzeBQ6r6Xdf)v(~xI zc89kc|A&koQ>k0rkhR+AG2=#$`SiFRQvdXMs1it!|l% zh2OIs)?@9~>)X&LcpNe3Am8sX@ALbeufF76-k znHPHYn72x8llZaFEBdTVsCC{q6#W&br`I@1{Ur4{7g8qci)X*WHe;QlAAB8rYLmT9 zcmUxqO}-lPx=}UY8Cp%hW$~loSsi^->mk0Nv`z9gQ&)`dOZu&uU zd)=2qUZdX;WDuUOj2Q`88-_#ac2}Q;>%4GkbxkPMKHLNthSTe0u8c=XHQKKI-WhI0 ztplFk?d`S(<(vqyEf>6hCF9KQ9u7EnxxzE!-LUGZ38=ea_`gQ$ z2Sk3>g4#+p!+uWknnvoDN^jheOu$~aFNA4UF_+LX>iqQ42?vj$@g;`2g$ zhVaQTGT)@Kh-a$}o^3FA*6sxi&&aljqbpu%)N&d24*i2e_A?%903bUwyGkYN?Xy22l>XrE3;@U3t3Fau6SlgxCI=!|_ zc}Z=TLpb~EK_hQ?{?zE6)V>UB!|(mj;Y_rTHmiLY3(ldWN#nw{Qk_Jf*_TWV}7lW0rB^YxHV%I$q( zGYT+gr2U-igEHO|K7NNsI{@1YnD+2H`wP?FJhazrWE|>BZ1Zfnd6xNnA2H8<1kdun z7Hds5GhN@CjeAW+@7J66Cz<#0JNqN^K4|R&%XEw#b?J4HnHHblm}`91 zl+?D)`hIe% z(ewu4UnenU$oLRSJ!Lx;0BoyBBQE6G)JAbGwUg164y$zVtWKCBD9$T^255C$s&gXCGeD8QJg<9+f zv7s1WlE3WGby#p#=v*R_H$(CkS20ILRCJtLugqK&U(XlxR;+IxQaToGZ-=Sh4xEs8 z4BWXUKh2N_Uy`G(R@1>RpSk|&>=`cQ3-S_ySa;S&ACmimH~=2c)_nXE;aQu9xgM+$ z`7X?z_dA`NQf1l=#!&UC-b8l=DluD{p@t^PBtdw*fw7p@;R zaY+?cdO&Cu{a9Ipp6yaDp}tURSjc(ZE4eBD!{lo&7af_-lfW7;zApB8;tAG3@>UqX zY1+%_$JPwGLjSf1&fR`x^t>tUQy5M5dXk^0jeeRpWLWDv65GuB8CmvCAEl(B%cOrR z!B^8Cka1fVNxrtFIn6`u6MSI2HT`?2_olxG{kO=sgO|uITThv`H>>)3yLu^N zb6&0L1^rHD1K`nY%!7GLrb!;==e)qbP-Yc5qwYbI4~M)X<$Tsbpnb|p_ey`9Yc1rl zfW2Sn7y0vF%2^n4X-nog@(}Hw#Horqa*v~rD4vf%mRqf)zS)bx@`dE{FXOm47RopD z(x@C1 zf0XT?^Dc@#3pwL4F9evKa>Ch*@clyTu?c6*8^fAbj=V`7ceUul$)8R8P=1toCCXjU zs|4^3S0sHW<>-+b`&nt<nbV^1`^7k09)HcoyJZ1{ugolW*vh@m1UVWPUZIf0Plh&ZLDG;{M+b z>-wfOO6yB}zM&d&zRxq1?g{P(3;%~jFK{M40b_}SPl%IG=<=inlXGVf=Vm2qdMsxQ z6!U`92ad85YlE3RtFULg&6t3*HMloD;;gIT8s2@S_Kg8ApCMi{28lQv0Us1g<19$) z7^zF&()MlgW;`qVarNP1enUlDJZNA4YF!f~@g{v(NK4cRpQ|s@8G;7l}zBYRS?`MAl9@pL^x*oCFOB@C90eAp<9#-8Rc^IDW>_^KPtOv7MVupP_ zHxQ#=$Qs;R<4KGPa0{{r^9p%?L?0Jne;PZM(158|(zj=mmwO{WDm9j|r^u65uGX~} zB}UHNCyz6QI3i~l^A@f3h*M?M;TG|&K5o%xazYKxHu6Q-_X~Yr!|Q2>uaFv$z!T<5 zgmg3F=kLSXR@56?5Pi*h1xEc|8Zb%=jQWdUr2QM1D~2?n03+>RR4fYw`ch(x;yzqe z0;65%gMLkefCqD@N!}vNoxI4CNz6S){)_D|&d?6BU(UDB3!GXFoah_%5TE5-1x{-` z6r{(4A#cs@f6o_4y1)M))#|K48~x`aF`O?Bb+70R$pdqL^96iq@xOGx_>R`g^Br0Gg}(2E-s@A@PmFTG z4q5*o#zDD`=Nz%G2V?X|gd8@b%h(6GFNgXqo4&JKy;ifYjE_u?^hM&K$#+pd z=%ggKByCYqTox|yj9Eu@9D9&7pLqfu>a&t)GwJQ3Z;#NCq>h`m`^5L088nq1+p3!jemZEcHTJ7MfU885~% z!u&Lj$txlIHYst_%z;9m71~?5XE=8U{HcZYkBTo-+{85Ynf~LMk1HKdMtN9#Zg7_B zSg#G9p%E2PsR6WM{GC}vW0iOlw(T&l+iH2|GQOkMA0sRRCT9TW!2CSShZ06R5%Gu8 zZIsJdR%pMrsQotu7V8Uez_()v@2_|di;OMNl?^2+Ae#Obx81@ zrB-9zfk(g*o(<({y`r-Bu|0SGdOCq)QY0aDgNb3>RDD)TS@W#qJH=S zsnetL!cfNreqtTtX2iGE$XwKW)dD_TuTcDYH=KCPr9Oas_@aElM}_*Lv*j`2v%X)x zpT|To)*0jF+FM#LF238!_|Zhoy7;*TxVC4?E$}eg<(W+W!=`NuypzEz(%)LO;TY*} zfc&Pj(JhbN>y`nRYgPL(%tLbY*x1wj{40D?wvlmgtsdGq%<(6g69I(>5USe%xgIA*tc~)#Y zHR_l@gnn;H(D2%Xj>n#l-*as3OV|wl6YqyeGiS?LeG~QKQiHxVE&1{)cRd7}jy6ND zogAePY4h<$<=|R{YbP%D$@bZ1nM2;yOr& zjl;q_aGh1s#aa9!*U&M(o8*=M>OW6OzV%lP-X$%Gb@GyFT<)Nkif{K;r8ORl?%KUu zY?gMs_t@WKo~*g+ns=93I)C^|++U3QFPi%c%>A$6K79}*rolFC+8gA*+YHQTr{4a> znX2~pjq356W~#QtOttTh_o~Nn-EqrIH6Qm|Zl0-@;`4S~d+^LITz+1d0NUc-i=ZE| zPhlVYpD&*nd2Q0A<9>t!qjbvny<$H0-BLd<(6C{ca01@DZ;)?E8v8(8^T-cQAM_r) zdC)t8v4)*Z!;;rS6>6K_i~ldYJWacph%| zSdTeqYMC{e_QQs5gu!bp4WjMJjnej$2Cnm`YdopN^W{Z-{l2KL=62xZ*9WCW-)?Dl z^DzCUipTwOCC9x<+Ab?;%O5x2PjQXVro3M=KGxFp$9Jz8-_A-szT=~3A7B6KL9hR7 zdVFioGQI^x<2yWh_VL}}kIxpHq>Qgd#@C+Z*upxuPF*v``VVG|wi)ApqFu@g^zT_| z{yS#&VH*FjZ?@YxOXoR%sb~&v5__Oc&*6r%%z^a`{5kA8#~iLb2aJ=d0OQY^G0rn% z+$LuZ1*K)E^bzEv6R1sV+{{jDh2j>{Rx4hn{ zhOqZ)@!iHX=Z!|S691iPpB)@MF=9`?RQa(LoX2+jzdbSNRi0(fbXtWy^X1Vq@0sP& z2lnh4_QirCn3Nls%rP)obPkxfqXqjyGv>AT4Gj|q-&In>;!JbgjyW!l>NyG@(v~_c zX9Hzl(rG)k(YxtaCr3?g^E&43>wGmYdHaGU=N#opOZ4&ma+c99tROeDPEs|o7pnNV z(!7R%3HZL(W<4YP)?}r9z#q79f2Q9~f}fp!Ea+V0(pUW5N?rEL{ik%j6wX<>%u6UW zVk0JxL8Y3gv#vG1TD3;kP5F8)U=)Fze+Od=iu@=RkZ*N5+y!_xV8+(-H2Z_>&9ex7 z&HhN8UcnQ$oEHahZ7jDX~wd3O?SDt$B6^+nB>6lwFxP;@R=L zy_wV{I#t=3!ZTl&`xte?SWCubMy;7*a#YPxQW#XVW%)iVUq@nZyFXA5X zCdUtW6^R4hl(qxZb7Yt+h5C~S_%Odto)UfE0k3*Q>q`AtUF$gYFKVP!HK|%-%cG1! zJEZJ4(AHY|-9SDRT1T05M92Fq!#fcZ+sir415Ze~R_G$zq->Ga@?g&_(zT7l#C4JN zSU*W}=|dhgIQDz`wHmzY@0zLl?tHKCWsBKvx=)@{Vjo}cwa+TFLmp{1c*cO$kyZ4W zrO%PB>DDMYRl&opF6sYw)OVsE_QAfy2R~ut$2M)-XFj;|k@pUoXHUypnKXKim~Qu< zGP;IMxf(deS~VGw#m+3ZQD&o@_H#V*m$FqTc%ojUPd%LZAO zd+<^G_qd~TFRpp%gz?{TWe=AX;ZL=RP2_(cGXL#mtv8&t3ymDi|Ng@K*M$GRZ0<8Z z4CA@{n$#=J+5Ep1_19qDJ7C(JQ`Bai`H!(peqWPJo6MKO^QOtPxx}ZuK zmv)UVyaRZ=7S|SBlIz{P^XbAks_3&ooWB>(&>y+Y$ZPbUF7|Oa_4g-?Pp2EgGZFF| zJnug@tZhByF^L0h)RW_R%56O_oD@5kFS{lG;l%iF%5V0!HGbY6*L{@%Ki_o6BnFkb z41F$XensrBc1mI_%ayKiz?>DYi~e8YF30r=#y9l|$p38OaiUIaMn82`z6#J9NC%g_&@RqzjZY5bCimn*P;V+Jpmm*VA&TinHF zO^zNrF-l*^`R2Ea-!aleTjS~>{I10wSQ1vk@9`ev2LJt(&g)SjF#p-H+g>^`zW%$g zrh9Ph#TAg}3p6_On-e43zdiG`{EtfXN|IMe=Xu0=|H$W9i*@y}W;N*Pdph1R3>fnh zaIO%$7`~55oSS}k7wH^mmgt6*)S8#)@oW%n1_0|wwHhq5B(_w)|9Z*$<96yk%J+j_ zTx?ymL3}>9z|p#C%iZd2p}g&E^&<9GFPh%!wYt4t3+`9P?#v!n{l}V;TfOGgR&PG; zJGeg&pR@59!)L3zRcJ#i_`^A_*1ODicR*&R&wlSqqW{3zL)}X~&Kx`0>oui%SxeVz z!LuASszwH>?%>uc&fB8)##7`xQnoW=V>@7FDi zYPv|f8F>%)7h{s^kn-$qz&eWcm};fO2Z(%22lh?aoase6`pltUkBv6Teh1${KRml{ zxYikzbK8o4a(W<^oHWJN_Im1C`nuk$j(5!*kL!LC@7q{6$uESx8l1IyIFEb3eC5{NG!8*-N8TH)^cP@_B5#rb&jgKji^3$CxY|NdAD{`-pj-y;97(9awzdgkH6GrMLL zJ>wNUGpWUW;-Jpw|I=@M_->yEvM@i3`YTK8uZW|+z!^>+=Ct8bFG-msDr?&A(FZVs&&kdquhM-OzaN&o0FmSULT3oS$<`t7uYWN% z>eGZvfiru{nv~D~vrokuNcbL+dPq;>deWVNg|KqmaDD;Q5#<-oMXW zuzQ>XnLYNA%pPkf!}}psDY45B;{JoU|6tMma*+uk$J$3A;|_WLee_?2GdM&$8f$pB zk^h9O%ke#De1`lp(4Xf8W^Vse{28?#w^&|`J360l+{BlE#D|69F|03<-buZw4D0dH zCdpWd2;;I@^F#cab-s>?a2OCPzf9k0uDof!=Vy590VMO0Ea^b zIJkg=OE}y_zpo1F(|tP2d=^U`owFqJ4s#V=2=i>kTt59BPtxv$|DG)R?@99?_rueapUr;oaikbV z!V}Nwko?GmQOx)i@C=&g_<5ZQ`BFomkw?MvTpZN-GWZ;u;ClV)b_2I|1J79htPT60F*#xGZN`O(|3Z(Kuqjs*VnWs)Va?EfIZLOM;D9oE z8&#B}GN^ee8B6&1de5f?-wdjeBw>FB`tf1(5l6qw7scnb&ZXV!$M|nQqH|C19G%#= z$wN_;%K^{ShR6HXG?o1v_hq*PWFYX5$Jz+H&0caLZL$NyA*V}ZN!E$J80XS%JC+rB ztl?^xF$0Z8pAdDqzT6+&i^;5SYusal9!cEXq6zy+>W9hmS{K7Lco5G%Xr7gP3OGY8 zlWzfiR0Yy_H@!^iU65ZP-$NT!*zs+>?c4{)nw^P$BRVd=PwHrME>D{M#b+rS6Ar~P z?2Csrj?h=+Cx)I?$ovmr{`1D?U##OQ_UWUJD`4=xZ$wvW)NAjr&s_lT$OjdU&d{VOaK@)qy?7|Jq&Z1gBcIdHBZ}8>+g!b#(IoB=Tx-T)VZWC~*+ojx9j4OM^ z7YOIHT3v!GL+8Miz7kv+D#4YZv*HTl5jiHt{gw+JEX=TuUmMRI$c1;#eeN7%-CQ!(=Ss%<+&RbU$XGYYSi?nQCEvN5@F%UpxwjWMv==m*zR^Ano{Tl! zo$dl1?(`B^+wDTL282(Gs;(?`L#%sAzTx)KiTU!CGhp!3=#VGSYr>#IYH0Gm`SzfW z>BIB&==YO{$E3D2b711L?CYTaO*VO9{fv!g<{Z|%8}Uf=UWVRDZHtmU_|~Dq9z1C3 zZ?(w#i?hJRDknKH&o=*mneSNCi%1Q>3eh3ibI12zV?b&Dl^kPM-(H?cBS} zo<19&SPMR}#qf!>;1gT^f5<2H6!D22hbHoghy}?XV0R~ zPls#!c_|>D&@RJuKp&y+9xCvbQA^ji62JG7Hn;}kZD^lTu{X>QtoOe9Q|3CNt!dE9 zPg7ae3Z|S!xea267{CmeX01SkRB?n_|cmHUeQ=pX(ZS<@lbs76TuH%)!^MAtolhxB+mgiiOxlp&rJf!}m#r&$9ragD(~79V zGuSsDG4XMtr!jRhIF8Tf3;MP|MVsIjag_OoeHnqdOKAs{vo~awizCKWbuW~KWm0^APD-t+5j5LY$s8Xaba zdRYrHa{N?&+%7T~I*xc04v-cp~r1?{wg){^E5 z4#nDe211VQ@U8|N7?;6!=EwXzs2jW$B4=oQaENwmUJdOo^P_6}RG+s1?^13kmX#Nm z;-o9AcadB^CfmeyY?a>Gs|zZ1r^MTAMS%~~)fz%qI<+V2?e$hExPtR?^B z`h9z>kZ<+7;OobAZrCf$I1iqEVQh5m*SUUrzua5AUlN7=LLQ_1e{sK*|Ec@M1-`o6 zFE{D^0^FhvrCt^7mvr$MhA@UhXW1|G&EH>aVva|{$hLa+};@n<-G^-Obg_h7W<%g zL0Y$ENlw29k5!wTeq2lHo-Kzp$Gfu3OQL0|0f{4>C}Z^*9sQ0H84Iws4`udN9xjow z09V}KJ^gTrj0O1GhrA~1@ELW`Vwa1#v@Z*e691KS=Le5XQ~!QUiLK@?<5w=a+PYTr z-Irgl1HVZAjb~2mg|QJ|?khukwT6!?rY9eMpkKFAAV@299oAGR#(XH2)cBQrMm;f( ztzY7&nTH&>bs6gv-Qn{7-CoG*8xA>1(FaA(r)~NYSz1;$eh+mK=2s$(P4{Hk$8bJ> z)w6&R&#UhZpBmTM6TiqG`#wq{hs3m=m@-HRymH_3y1pi3gvkr;V>_$qzo+%;)oq<+ z8Mu1CMLYD}!ws`_eW}2lj!a{7yUSb;QTwi8zGratfvB`|xBT8@#?AfY z?}0lwueg?#Ik$1%8+;u78z}?DpD*aBe)ch~qw08G>*V>44V<0yx%{{ucqP_r71o1x zchHX;c?LOileVn$6zYG04 zSvQ8fsQ8G*d>^sJ87*UAzZdJa7hdi9x~PidTCZY@%*{3-8)46B-?YVS%vdzL-`Gm|No^9YB0#9(U^9*2qb#}M)R7U&LUG46f zb0EWW^?sa(Y3^BzF>JkF!;sGLc)Gmv&Tt_7Sy#vcZhz+&CuQ9zZ^z2%cjV@p3UMlu zcS8JaK{E%ycir*POO@o`i|M-d^<*Ejpt7KuC4PQ@tJ@9%M)_W ztg;7<%-HUI{WqsZ0sqnBT7YbG!&lYlo9JsPX)VTe*H@L)BW8}06Z!lT^9&EY=Bp=0 z=a}!E_&!^BUj5sVa}0bYua3Xwb^?P zQ0ftl`@w>a@4>u6v4P>;Y1*FqgtbBHC zbb0K6cOO2*2MN!I8#WG;=8)gqgm+rIXR4ie?*cUhzRn__SVet!5Z~<}WNoFU^LGHh zsduvEGgVb)e9(ht%Wr`H+`)f>L)Z%K9lzsssIWO=X=Qr$hP; zIt#Ll`wPcbxE#+B(7|Ryr_Tk4dH)M=m{bA>2mO9f#@pwm9PM+*_!;KB<-92;Hw!$L z2|Q?@4cLUoBIcHRk^MmaePXiqLEI18_(&O^RmT28xisirot@-dlEt|%dGn@%9^%jY z0^q5`*hjZCH%i^>TlS@dw_u%X`p1cWCEfMo2x#b3%|}1L{T>KJDuOtdH0*8`*zGTZ z9ciiq*e&kc0s6GnTmE>Hn}7Vt9BUjz+^temyE?wZV_ofA7pF2U``+WSmNx5X*Qa|u z$fDlQV=vIomT9(nJ)N6Y%iV#mce}N2ugIKnw9$kyM;`}lpX|xB?8F(Ie!*+O|IFFI z_}^xChnJ98OXl#c&rQ9$+YQ>QWxb--3y=q**@nwIM2?_e1>qe`w@(kG+k?#I#4|i< zx4Yy`raI4gR(yx&*I=BCHMJGS!5kG%Z}w}XiAlj{(_smGRw`-zdWSAmbsqyt<91@B!Fjw zcs7oEl+&JX7?g2SM*!JsR=@#o=zK-saV_^N#>jP!ItR+??nwn&a8A}Tj~32mo*f}) zot&|N`<3iFWMBz6{g~%>(EN@#n}1wp-@F?%YInq0^Wzr9{2-gX3M=XQV+wJcfP2_l zgK;Kdkaf-YT`PG=B)+n)#ng2tzqI>` zXEUrbJi~dm40JCz!+ETXy4_~9-(WxH)jP~R+ih|*rE)FtZg2NJkKy^p&}aAf8i4!a2Y$=lU3n>p(`+=i<=-SDhy z+>q>v>vO?)$MitFBS^lcEZ*V%?SZk;@)?Z#T?5&F{jiU3!T9R`(H39hQIGN617jn8 z+&bg+Xw$Qk10HkcF1H4-UeAMf|B^nd9wKkN!mTE4O{{SHoq_K~V;!kUzAVu%Eof%fbH` zKX&Z*ZRAUV*OxVyw1;!HZi{Jeu4&I-H@2xVg>_>M9q=b3$BnLyIcj{rXXBqABD^kE z+FwO-W7^NN-hIxu1wQ;c-529nO7R==WZmDHv0QS7v8-|@j)is+?w#9#tDhjeW6ul| zZlqtalD6r8bCYR%QVHBz(xzSDq-FKKH1*wl&Xqj2#P8RDkJbfEYGrb!YQ^V|@O$Y6 z66=!l?PPu}OXlOYt!=s{5&4(&x@?dfsT%a6vpQrygc9qABO53uekxm`biK6)G3V5ROVzHwJoB~K|HLy#KXWNyaD5Ka zRo!g~(y%2`1M61iUjjX$et@~KeBP(c>X-dEV|Js&1_Mv(eu4QkU2*za{ULv9!dm%t zFyDUItW~1di(#$qsb|i*&TK_i>sg9@a%+#1Pe|pkiAQdW@AGa=GWTC$JpNd27oUyI z9`oBWx9tV$IgdFtnd_FdzRBMwDBmfS4cU}&pT_^s$vO&OQ+c(aDeQms^nh9|G)1Y^ zZky`#1~A9i;5=xZ^an^Q7w@ZfddGUI-q8F!f(v;B}6Gk6pm>-;{9*{1Cc z_*SI~agXfpHgkTKDeXr>zK1w;o754w&crmH9S^BHoToa+eGsD9CyaLvGwv5KYc#$J zNK?zl@?vu<&I?a{RJEL)o3!m3=Vrp{o+#^8;*5oyR}CEPcQ$x=Fxqvhe1qj@tlJ&V_nS+HDH^ z{UG-9!SVf`pg#mkY+w9Wsn+H+#L^1rB*Xw+}M@IXA=TAA+3tNv{;PwO%P=@Bz5^FBA1j zj~czwqoP-e7&-dCQm=Huizh}7O~naVq!$yrR$AKyWKUY;SF6M(PF*kcYZ7OgCe7~k zK3ZZQDBWY^NnXZUaj(^$;r;i&l{fZnHFB)`bX{FB@5=obrSH}|@UM{){5~BBCH%aN* z(N8)P`}qL+$(epGE8-v6&ra+mo+CeT4hT;3+}ZLD{H$HV&sG-kvr}KyX9N9J=ar0u zH1r`ej!4Nkn$rb7CX9=D*xKqe-&yAKoxmk)n&CUAX?}CU{)nAnf5gwcKg!HH#mqXD z73~l42XltJDE6QD6*&9A6S8JyDhGMg^Y==Wv5shGx||1UT`TqJ&d{*2e~jn*-XnYJ z;S8VW|Fr8worfXkK5g23SaPd;&}tGNB<>CRuN1F!)P7p;E2mf93uB*M`GU@yG0)OD z1SGz)Xs-p++*`|XvgcgA=PddU7VW2b#?Caa$j&5nJ#a35>(}~RoL+J+P9=Rmt&NWH zHu$WzmoR4@_N1lv9Ub`hA#l(Aj?)Jmr0~KaVjv z`27V-+f>Bnm`Y{l^Bg7J?_n68~nK8kzo?Xq*42N9W#K{F>eyGbyX%clhr>{Mexksa-T3*nEP!$FTM={%@;~;68cB__q1MZ8}OF4U)JVwbEUoz zt8Ch$U-VWw&zAU$KIY9Y(piXYp-tP)h1YQgsQ1X~HR?L!8bxG{&Q53JkDN|ttBdF? z=1@g{v3uUu&&?^JvoDv(x>sQShsNpOk~7l3iwyna_{)U`?iW3lzphXHR<9Lf6V^Ht z$HE*XNi&vwPOO$Uexme>$m7$|; zmZqUS_}oRBW3iURT;Rz})8|(K*@jEDUT`0CRANPo3w8u5%^P|cz`r3@XiHjU>~h{ii0M_kWX&&!sJPX~3ux4L10 z)u!*2711Q$*C7m;_4_a@p-D9PKl89KEF&CX(T%n^3#)F1 zc^1(&+nb}Jl2Hw^B6`V2!6KvDin`wWv)qSSK<;A8KET3VWK1k1s!fSjLLC*;jQW~^ znisuiW;l0gr(0BZv!!K!uh;wYIlHq9lHEVf&e`+uIiH93^XL7L^`GT9xDKQVtlt=l zH@h6mLCLp7dZ_bENuAAR)`t_Conif|v(S&=AGU91ZIuPfW~w-j)`DXxjs%XCIO=fR ziKD*Y{yH4QHTIEoj=YF|?DQuKIn1RFo!HU&qM&z?ma--fc}o9yhdFMk(`o)gIBA-T zwW(@yTgqEp!a^hU0<}@%k9JQne5GFdvT$FXYZ;i6%3b$gAI+8~Hi++~9qaV&es(ag zWNw;ItFuK#XX|`0P(a77y@`Nm1nYw%H z3A@FTljsUJY^}|bc3Wos0@euJMj#(qSi3KpwToC-JBw>4{9?woUuc_96>*c}NMqb- zjD<10TNACx*PFA0o|qBV7EUBcPzpf$t|)+Qj0 znotFrY>(FccK;bNk!|Jxb06T`Yd$Xf)De+urDnkxJ5HC;F?DSsUtZk_I)B}N8F}XF z(R6_{Ve0FUuM23xzy0JNrwLaZnlQu6?bQV|p>_;Cxb38-2Om@PXV$p>5pzy@u)v%L zCu+Oke4*@P2td~9dJZQ@+QZiXz<2DrQuaJgnQT&j_|Bab9p z{w#f}Trp#eToJ@?$a+Ec?by$$!Z+TcAArq;fQ9)fzyrp^`ah?@C2LS%?s@>1gqNwW zYu+dOAmlf|yJe6E%51$q!CY6iC42qr`TSEN^D&p2*70`CrCz?x(|N16jQHbdY_&bN5+;CA%A-TTu1fxOGOYRJ8qq<$w2 zxWgRIiD}uG`uD&y^eNopMa({Q=~H-D^4o8a*o7+&=v@1Ofx#@@*}SmFBb7ipbBXp!i1@zfO1kP!D@W8|?I+t2@~eOfnT&764B zTZ%(q!E$rGPOCRGCy?DAKR`bKFP(0c{lrq|fOmnBZHtXwFkd%+;hIz;wJoQC?Az|h*LM2#`;#g{@@>}r*8AOR}f{*GpixX zT-jl>zH5huwzB5ZvO>KvQQ%9QhU{5K-K*Q9?Ni|2ZOH~=_Z^$$>yE?&mwD|z586fj zvHQVEO4BaFIP;Tn{YkshPn>EWrO#Q9{lY1>Hp%&`^uFNxFz%zDnyGlSe0t;{9r}b> zKeQP*m$Ho8oMoJI#E)~vI&y6oGr+ZEymR3iaeZhP<{EK*xHj|XFX_0so>>PnbFkKq zu@##*blGbeXJjjm&G(_Fy!)nElO2E5HiG$o)Hax~(cS2?JukubW$z(JU-P>9$99G> z=Qe#`V@b?qvzx@4@|lHkUH9iNLqq%MZyjBKzOrx#PmGV~_#vzhYnYbRzvkJg*GTK6 zk4F#Cr&|0oGvn2w4A#Hu9jrNLANCyQ$}IOM#*r>oZR+DS(!D0T(RH9d1j^U+5$5P; z7t#JE#q>3qAhOhaskJg*bXMpGfUN*wEY7?sarusCa>9yUf^pA*tS|(a(fMgN2riKp z{fs$_j7?4SK|Du&mU%3O+)y?e-{!H;0q2E2`oz$mi2FqW)sUT4L%p(DYKri_1Gt%> z<+}C!-@tq(3Z0|TX>xf#1YL9%eaZ^j6n}r<;%`j6jrh66^j=YjbR@3r*6jOivFjc7 zSWkgAGaEc+b`@bZ)adJd%y0U2TrZV=9QLXd{n#OE#^|S3D{)jI#?V>UNd9@^$NP*d zMH}=Qlb6=dryj;Q#_8ukJJw2W?nj0QTdF@*exBIFA&zvx+ZpjVXA;EvS-xrYn zE;^;ZBY6SiPQJlBTxK18TR-7a zB^G5%>t6E+o0CNjl)8QEIj*3Qum1g|K_f?Siz_vac4q%RajePQ51D@OKILBiLguB9 zRX=?R*jLt}VH{A@Io!v*VXSu}{{ye+7iELajqZ z06eX9He}~3<_<_@V)Qk!m?wXON7;dSK{r1=n6HUJMvhY-s2%nXp?`*Nw=-^c9|OlZUrSE>E@_ zwYAU0thr5Y!rthGZY8~5LOYDekd*=GPxhzWYK+7B*+722z(Bi~K)+T%4hy9}<%&-m z=J?pG?c%GaVr?G#G%jWKh7GI|7m7^3!YS~&RO*qi+UzB&ZP_%}&JtgW+amalq*=?}W1XDR)(zgI^pU>XjBmwlCE!6N<*vvx zoGZ{t)-0!eawVQ$h4<<(KdY?`Qj3(|tz>SebSg9-W0;5U(&v(XfX`i_W#2epg>kA2 z@k`&|X!>3^?6$ZT_?*=K0UUH!ZTBMa*S!hu>sY6D#&BdQPe#)npx>Wz?brs!uX?|M zUK3fw@5Xa>oHgaahg$E+(zlVha!Y_?tflrcooHn44SIH>YBjn|yRY>YFRE^Wj_I*C3YtG004pA0Lu<5!oxj z^-c2J(j4c$%!Z63PH=A~-yvmDk%+~%zWOs=MXBl_#hI(6coxJ}y{R8uBVX}bxm z1ARrJ&Pq3Qg~sDqSQqkJ$~dcOqmI*NeuL!Ue)fO$80pux3^K%O>Zkb5DzqI)CncV^ z*E!;?v?zOT@E*lE*JK}lxduN@AMxt&4*j98#h8m?I{(Uaj4^?69c(#YmAs=uC2<_Z z`A+;2mJ@zGZp@Wsul1HOzXoAZa$*235_->(zOE|n=0Z+eALE%>o3OX-2`;*Wtf_zUy!5^SWr-pJ*?XKDNDmK4tb_mKr|QuwUco(gHgP z`IK`CpL$_5pSps4s&<%9{StGs@}~oN=M?_5!tkdR?r(km6ldJD+SkE2GRVFX>yP)# z5*xh7XoIng{{!&lrv1JzQ|gh5IP-^Z6FjM?2XCU!81;0tU24&Wximu_QVKrs9mplL zlikIdRalF~hqas*s9!e~O5Tj3`gK{_V-mM*_a=aL7sXiTCzW~q(4gdU;k)d|)#km8 zd`E5Sdx`h!*GZk;nmBM8&n^MZvF>MedV|Qn^YBZ5Zohs&Bi^k6Oe9Ke;dhktNTVnd zl>z5~C!t%uzVZtCRxZx4&SW7iJ7R71wBO|-=Kdx&rET*&m0>jUw_UQOaPZ|_%Lqwk=uEr+@E>v$ah(Lnwtu{)sCQ|N4mrnB)i-clT-v&?BAaIa`rVoc%&tf%II^RQk~Tj%cf>1bGJLMrpZ z?+ooU`(0(gQ(j+%>)eOx`NsJw{>}<~?mV>=zg_sBvH@+*pM*T1<0qD87DEnx;kki) z8NR>jAEc$*e}86L8d!d!e>c9n2M7B@I!gKd8<)3a8P{r4PM+1`G3GPETvj+N93?nP zag^b(am=xrybAnQGB#8(&qZA1`;t(LN85NDWAtO>Nz;g5^ciK}Swo97dzvyerSZ*K z)fygnFIbrhSk@K6q43mPup$+R;Cylr=d)6QFwR2(oR_BpL7Y<;3RqWs)3zJ35^rRY zuHKZL;4mMPD)!rzI0b1p75YcoCG4<|FJKParakRGb@^3p0P{7qDV6Dpgk0HcAfKp* zt^poG90}L)dpFQWe=BK%?NVpHJ_~(^QL4pr3ilhCbo^Df9{F zp#aXGM4xa@-9O-d?3>IDMffLvP%r)6hUaOJki;l``P90yJ_!W9GpU%Xrs*1-{E}UFLr?2+%(<~U6RUh%}djpy$6D{<;F1&tK6uQ za6<8v_!LqH(sc(?xs8`3-Hq2&xSdy4xb4#$-S+clxt-uih1c0eMG0;Dn=c7jw>tPe zH()i{5wY>9t%RX~wbETe*hBvakCCc%!}}VF{WW>lCt`hU_Ops`+2%C?w%daNHxgLq zD*7>_&-2-iejc!~_L7Kscdp3#Ym1H=zZu_W=N0pR7uLOk<7V9nz!CJRt(900+6tqL zvrF^(;>^I%(E3XBQ`Ulc>oAU@;c+C~iqYS1X70c_oNx5)U61*;qqX8A%>Fz(GnM;+ zy*0ykOx~x<7NAe1v$uMWI9nz66J*P|r5CTignL0haMnwH4a%GTIrFCc?UwV@sE%pMS%}CWr+_DTteNh zL1=o|#`_mDPgMifWxKS+XWN6ywTnno=r^6Zm~?+WzP}I$pN|EZ2QH5Bq^fw2x_VgW zRGq?pedD6~tni(=^&azxM&$a(S+HiG;%d){o9G@H5y^QJgr!)lPV z2|G{rUHKwtGhmL_BPPeca;_hh$5v{J3r%VykDeZ|weO?9Mxuw{`(p^xHENu7 z{(cI^8exu4?gJ}b*M{IErt4=7*zmR+kz-&r;u4)Z_r=K2$i~G+jZS3MZO9 z+U54V3wk+@H*ipYV~#D!%MQL3x}v*}x*Tn9k_#<9KRYkb=`pv&I1@w4y&>PvZ260R z9xCQ3VGL7kj_>?|c5%w6O4pZK4fyA}*;tchw1by(Kks_Yf7F%P>MA{##Y)%kA&!q9 zv-f{G*zjwVvyJ~Tws>CW_k5rBg?5LRq(6ILG4tT{R;!K?*wbrB{#zWdbZ!r>;j<57 zegpbB+GL|i#G+-r-ex@Ze9iu?7r&-_%s z*fY{U3}nV#YNUqGvwH^m=b3q$Fb0>EfpKNl%h;M{T$MPHmpa|2)D6%%fLS-dGH@Ds zw}#Ujf$W6YIr#r3oY&yDdc%36_O(jDU%&gzfaG-RAnshz>{Z8_2{ZV=*?S%LDxAY! zbwj6Db1UmTHi4Hv;{{WPJ^G(j?^Yeyoc?s*N!bg1L-1y4 zPRE3$GWYDH@A?wy2X!VVw#KXc@rg10=rsLk9@P)x`&RU$w1Agk&5OGxuwIGY+ZzXb z>AqLzqq-%n^Zgv3^+Kj3#@ZCu5Bo%N|6Q5=ciR5v0Y*QZZpn&%jy72rbG(@^p3~;d zwRrr4hqwnvx#rayCnsecDf`pT_sbmv`MWRtdG2!iDdtMZJ^oqxupW?nxjWI{1DIEy z$E(`C=gfHm=S7e^4)TAc^U?dXx;GAbyy}G1=Of(J18>h~E)9&8H3GXuuT5o2ck8*f zPr;GVxx2<0KJ~-zpUl&Ls-i0CB^>&8Z1;McUu7Qu-~pjePI=O+#=ROG9IMz*9XGTT z{}-K=%yLhf@$x?&cOuU@c=T@r`AUPgD^8Bo+93|r;5bx2Q_aI~Ps2>LVrGRR{an3? z^__Jds%6S;QuU9mJ3jY?jPNgtu|9I(^>3Gj061%BJuXC|7xJziT0eBY15Lf<%_C8i!Pc`J3L66nAuP7d|^ zzF#GEU0%_5*Jh~?Tz;F%&nw^TiG3M3$=a2aKck6jvaA!zb-Mo+*7nA@;_>YJutxi1 z&p=;m_RK3$^QLs!wKM`u@fhnym*0~I9RXOpEPVb z>&CWfUo!ea^`u?`9Bu(@-<+%Ce1OJs{5MEmyj141##Ti?DEe*AAJp@8yHfkYXt(H} z)@HTcdxLi`)^lFfW>3C>@iUIPn0sPsU6%0s-dl9dQTidW9*5Ki$6UDk2J_+iW^eCY zz!7c7sb()^&vGL+`J9HgN?G?cSqtq%Q{pR?nZ8cf7+A>f7@Bn8-=!vfhI#Zy{G=8$ z2FGKKaG$R7*{Evs_E-Em^Bm-S`Wl5@=qjq)n`A$g3B9K=_sYNP_8C_lH88Xaa%B#1 zPamUW-#Q`wp@ACo$)@kvNPnS!&bSrxz`4`-q5af8V%EK!JP$mW^{;}rHn|bem$peR z{V0BI>sMZN`C5@}7&jciGd1OFg?;h?QZk-qi=+Zv)La0e*%3h?E4HU7jaP&BbGbITvtAWpm zuLoi0hkw)ii}cl+Pxx_k?osL~^Qt!avYp_}4~=gspZ$Qr>#(yyazP%Sbx7uuV}HXu z=Ll_bB`4y-DqZtADEjMT#M;g@2&`%M&eORlJYT=+Adt93Nfp;IH+$eEJ9D}iwSDv8! z+$r-G&}%Y-a%e#3Jesi#u=@B159?giHt>phUKxv_bY8(LKdHo~=(l~*37zMV^Kj(f zCaTH;dL%YR(4ufk+j+SM$9S%Y#XUIr2uZA_Zj~w z+A_}YJVJe<| zL}|ZN`g!i1bvP3>Fi5}X8w~H*g=a+fsGmkYGUM~6eP7=DCa%?{nPOcjM)2veo$iAmovGhW|xQkxfVE*`@qF zuWF6w^UG<1>l?i@y;D79jaOryAIpy`&9jx}*%~|x`8zvawI4g+&@Zs*7~_VNa}UOM zRhD|$==s=W=0n$lSa@qQcK|G~*odKBBgUTW0Tik;)_e&ZT^gFLas@CC}_ zCGJMABt6!q)NSUYMYl2P-hJlYy>idz)eAE%-ohvEEzp1N#nDm#Gxy?X8PDr3&mUwCO;< z&s=~1KwiVs8t;K8nO~bYkn~ER->O@a-b+tvx=P!(5_xYizh6Y&A1>e<=%dJ~;)j<= ziQYQS(3s~2hVq}SyEaSOg)tO=wr*{9+$lV2w5`s^zasKc>PXHrv^nI07U11kz0gXjTr}NoVIgTcg$2iPvkmr zy&RoK!i%@k*0RYfW&B2p`;&mjdh)yL>Dv)3b?zy;`(3~h>q*8?L2lgWm8Q2q{%P}A zi*gx$Nn>_Wri`_C77p_I5@UBQ0o;TQOp<3a_r zXuA|L18KHnXm+W@ceD<#H(_8cV1P1ES6!!9hV?17*1BC*v)2vTC*iPm+M-Oc)8r;_ zFT}lCeAk(!vcKs$`;w7!OGM7?7$xUM#>ly!_T>_M_uPMgmjCM8wCAN{o)=N30quC+UtE7qkZv-$4`pxRSKMF-855?7Ym$! z|KvZ+Z|^w6cOHD4IK0gp&i4rV!aVlzRI692wu&Du{ro0CPNuwFVzr8WC2WbV0J^fi z$mhNEcZ=F>petKXPghz&S6Y3#qW4duts9Eir}2iSv^{=OWca9|Dfg15;MrS%%amma zpI=itM;hN3K4mdimd+so*)_D9W5lyxHhS{HhBogGBgfJ%{5jmOa9)&{=35l=lhGgV zrp$Hp<)V)$b?EqKT>3F2(eF}wv-dRkZA|FM4Vh3pb^qX5H{=FCk(ym(=m%x}_dKL+ zqRb7s0_#!aYCjD6$ag!*V8ogh38fdRQfI57FG)jRwhDcjq?To(@zf6{q5Warg7#NI zcj$tSTx6{QjY)#Wbb!Wm2#qNc8j}C0Inm3-)Xq+@;Em|t@pSA%+;Quq00n5P6JaG)=>Ob9L9>R zmt4N=TQle$eH!1`I#XhV8otLq-6Z-W*O+mnr04VvIZH9eM4QyTz4qmS{7kccZ}rVT zJ*M{x_&vf7*Aso1Qc>XJBz!%+(F?{>nLTc|7fNt_SR*MF(DuqyZjarPZC63|9ru=J z`7Q2S1)U=TUw0^Xn(Si@?>{A{YgtCe>d_Bs`bn+tgdsQ1V@*>fwL1gU!{pi&USoZA zE&sfC@1WFZCf_FSq~0E{1D?eh3$a1+SuSX0?BPZ)7MqX_)W1XY_0N&_{ZpgZ)X2|h z7wcW7@)IoGAJQ_spZz7*9=a>z5h*`L#CAmeyD>{yGJW5Gw)ZQ&_dveHG5s7ojycW9 zJJGiW`lCQ+yTo>yE{4u_iLV3DHbwudcRcF*VQ=uRFl*}bX!6{U(sEU)v)23ij|TG& z_ik{o1>Bh_D{Hp%+4pa1$e_hne$rwQYP+>`=* z#Pm0r3!Jtw(r(HOv{U+fhC$)+y6!P`Ptw!r0#EwBpM&TYz!Y`m!gh+3mVr2rL7O^l zN@V(%@oZuH0u$)>;A6z2Z8C=M_iCHX>;J6s@%aF39(${qtx6O^$H+0&>u%wYeC2SLM6$)iY-4qZoG&%DbjoZm zs7*y0_t!%f1I-i}SK~m%C>&VlJ+^l+U-a`e5(`Z~-k$<4YU|cW-Sth6XkKzY@yOmL zHYCpN7nIty$KXfQ$mDx~M;+;q_%SPIxx|%3O~04RcVB}3GcB7SuS+w(rq2tdetI!s z@&oub={s?nu{DLZLZMq&FOG$4_9>usZZQ#Zy(_!R6#@4SO}s z*$DWV(0aQ|-}mz|JxJHb0!J8)i8NEcL>>?yAN z8)=`u9yM~*Vc7@n65E=8eS*-Wj$xWq`5%g_e-ANPdRd%hAo2wkdXq_1w1y8Xvl`Fv$M1zd<5?;o73o7w--1*3v_{(mIWEc{;#+_=m@|-jYre0-xx{02b}nfA+k-d{ILTZn z2HwwjUVJk=>YL99Z_{md0w!vOMyWujtl^Xbxq|*eb;fT&b)OVJ>wqfJc181iQNi<^ ztNG^nH~xcgdBbVs^tbjisNbP&Z`AeaQxL$ROg!*T?)|v5<!L_m0w5#e7z@HBINnj}o;!}a7J5#tRZlyx*mV=k^S~O8z#m>4 zko_FhFV8vkS!2@=5nmJOw&`QP7gpOn{!Xb?YH)C9h<-gKv5j7}#XO}(9#)H{QMTn8 zsN?P49><4~#kq)yrwduZtmU*Y{v;Plrvd?MYBqRT3(u$2LjJ7Cja&k+K{!^g6KcH_8c`)}rWe+96eRKL%Yaa{pP}WG?VQu$9 zfsK7!cdbLm=>O19cnw4s%ihQvLqo655FT=a^ev*6WWd8B)MIH2V=c~5yweRQzU3M} zFNhnQPs!mnLm8W=-yUS+=XuTlF89(4@Bang6T76jCq5|++CNS5q)CpQMwxfoO%!dA z4)+>29&-ps)E~e?+m-M0%YOTPCcGt7<1xShV{&IWk~cXeK7)+o zNdis-f%ZOw8|Z6;>1!inp&PGq#;M%LJhUbDZwqH-ye?P*xNHbOl`nmbW zZ)HAOPWuhcfy4N@$S{T;=`=JEBN1ni1E0oWLPXoSg zIdCFB&-kmc9uS|Q&+7m9*AvV+*8ZDd{7M;TD1K!yYMzVXxg4GgBvO(y|E`%8suu^} z5I@Kf4vg0f8==$gYCT?t+9wN7Y3Ds$J86M4{(e)?=!_nxP8O;!3=yqMv4 zeg6tACtjH?(KSwmrbRTL)v@>5hf?^BpK~v7{Ax(oM(>5Rn!OOcXIgez-@K+_-#pSQ z`fst#m(JMcRez_=t4?XNwu-d+%i16L489vt@vCa{YSF$@+W)xgUhNNf*8|%n-q-@% zUV4+#d))z5%o?{ooGQE9TY52ggux4;PqA3GOz9ZHLi(g-1kz(SS6h|z#?m3+{FF(j zp+$m!R=0P2?g);1f`1Le&j|j-NRMje9{p}c`q=61nR{v<&l}apX6Ym8sw%Kq5(X?s z=Vu3uOkY~n;Tih>D&cGgb7&ZurI3z{jHR<+EX`&tonA%3SpIX=Sei$Th4=nua(xD{ zo)@D(ziq((i7u=e>u0X>YV9@ITFC*vm^PweUq9x93W6UHw`+`EM7bawYnPbPu+X2) zN8j(m9_0?^wusFKUtXR23w^&K!xtM_Ap$*VC7+FVicBPOr?WDC-8E0sciMjj?_U@C5M5dZH=%n}MGYC*KM$ zDhqhu@iX8>FYlpEwwE^ht+Y9^-XdkL2{I?-50JBMO?PBm9J|#h{3k4XlJz2k(odZ9 z;kg^3Q;?3Ed@~khG0^VLCs>n!ae7T2zq{-k=czk4L9--{c69vS-X{k7dCm93UNCIm zQpF3<&H~VU)_DIt`tbFK21fa3(`S!7f$?3(asR6ijrdnHR-x4RY1ZL7?SJ*<73vs{ z=&TA=fnx!Vze`Wa+t|PQk=!bj)xP2!_Dbs8yzx#bOSzA>*CO=4h4^mzM_ziT*k+j% zE0tN!^LQ_k9J7P9U)w zly$?$H+uC->$Z1^%{HESyFTW-YEOuLvjcEj0a@BfB(wESQrm&kx4J=lmD`HzQK!l6 zU|xURBP;=+FCcwfXzSeA*>9g5_66&`^ySPX(AS5Zv^$ge&2WA1`wxk(*HiVA%Vu1Fw`Zqd(C5k>WGh3K=nhU%SgINp18d=o%ZC(=NY;Z98he`qYgW@&K1AakK+A(XCKZmKj5`>*HU+M=^K2lQtKz_#_aHOM^Co^IneS=DKH zhkhq$FPHl~XKunSN1scbQ#*M{R~_q?uRX;cKkhX4c-sC}ecRvj>+%>U@wtaj=J#$s zkSU2Ly)ftU|!KNA^PT%muBpwETGaw`m(C?-QCUIbTEer(MF%1n0I^ zJl`2~*0$pPPVT7+{RACc`RG9Y6>F0h*7f$Zt<~P>Syn^#&wYCBq349O+_+8lBvouf zbK9f3hW9;6?OOo8xDNfSWPV|+8RK*68Q*E>#zfODX~$=F>Nf9G+#{vU;KocxUGwxr zYqQw?KaTs1m1b>%o{OIWUcHiWV$IoJ=K%2OaOPqBaz06;ik$;q3^<`usocaAYa%7R zUd&~&_Dhp*)>zG1(u)vez=`UBN8jRvd{=7EU$8=H+kUyI}uRY5~M_z75hu%I%D|Edid>AA|d;)QuU- zod~px>~a%pgx9x`r}T%dEuQapHx2U%xZFC?d6BeT>^*lWby>8o5qejf_i+7-nZS>+ z{*I=ZeCM<1>+!j-W*7&&@0!B_($AaB{%P3I(Az*mxo2sm*JQarK{`v{5lu^5T<&T9 z+0fA&eL4yn+GQ8eQP5D*(hktTF3?Kb8lj`p4c+4YVWr859+}f9dC=**L_0qHj%d4A zb-E4**CP3cPLF*jJ%J1{JyDmO4%$0i+j-)-xxn4GOMANv?LF&TKJDEiw0F`EM)pEk ze{%0yO^3M-X~-RXC%}ezEu)mhecWDy?sMba zsoeO2{-4pG!i;IW8574^|EOL!|K1~sWTq1D@Hd7r#O%)L^p{MOCq42>K1 z$|fru9Y;rhsY#~q#0ADi(&o%>$=>Q2eC}wY8}A&D+%gY;)5vJXo-;M!<}9o$=@5Ms zA&W_jpTEBt1mB#DG2Hi*_Hp~=qZ;p{hQG+z>{gKrcT?|7q%x!7w8Ow@au~h|r^EA( zb)7~V8opPOkngvnZ(Tjkq0AI58?vvZVY81yT1y%5XY2=P8uMB_Y#$QXL|;OW*qZ|5 z3~gCw{GZRqwt3M|uyJdcsPRr?MA% z=X22YR^zDt{!B%E&H>Log7ZDNN8U+TAe<0KX{Vjnx~;&UvBSGf{W^EG(zRvi=Mb|e zWa;D3)uUnMLo(loG7e-Y`Y3TuNG;ET!JlZqj(@>$fC)X*tA}_~2lHpbbM}|dPr}%WzdtB6$8xkk@^DOP;rH!=?>pKrI3a#w%^K#NHpt5CQ=50t z^oeuYd+8y-`7@bT=a9!(u!+ty&@m2qhrs8SefP|Lq@LLudnPk6_KY_XGC2Df75veC zlw7gtRA#?(MCUd|e=V5@^*sAdS|s~uK98u^xfyW%)yM548Ov(PvYt!-&rbFi{@;WD z`TNbZ{(TI;G9R%;%ylL6L4M6z+A)zaMOUBU(*(*XFH2lqhwyjCGz&ewTKu)e=ls{N z5jHn@Q|sMa9p@_*&sL+4d+nDnSFd`Z`USE_b}?kVL!c9j@qg6V^FwhRUpEKOue@Tj z_nG>2kOOPQZ<2jd;u9fxS7$_R*1^;NQ?{{y^N)ibN31p3bDq+B{FG-YU$FmL=1zKF z!#7wb*dGI9!}d5YVXmLaDDeYn_V(g`3v2o~uCewZ+w9vtD87%BPe?CUR`h>>1#a^K=R3=ZmjtUd^?o-O9J= zzKFTH1NUwNJsid*jBTZfeIxALg!`-|KtG?ARrIUx@J{|n)4^gj;)BHg%s-_+qj@9y zJ_Y?*X=2-$2b#WYAAaqm#2^!1yVKhNQO^dp_%Ytham|qS2lM~`y2%AS9)JE>(T7gkK`DR4*zY>sZ|1KqOKg)^4emei*>a`p zA*k5iqnz8bK%>e;->4<+-NinXnzmW9m$^V9%nO44U;V>@{6{Zm&5ibB+y@`0HXOrv zaz6oG`sxo^pLZMgUtRX|EHh5pFy6O&Ft5M)t>JId{_N+l_Up9LwpLv=lJAsu^+@dM zEazL(Yu0pFBDEG{it)Ega*SH%uph)JP5(PYuczNdVZQ(~ zGuW@Cr|s9NGBCgK2xHESoszNz@rVADjFYEt3iaqolCSeB(WyZrE?_N7p3|Qu#N1ov z9`_>NgSqW7_uqy8&&B^c%>RJ@%OXZM2heQ&fH?;Ytq+x*6AK|ncy9j(9iochPZif`^kRRE-bS3oL3xg7oJw4 zw##qy9;Mz{3z)@k365}P_OMSzpk_w&}Q%Z75Hm$Cf@?`k_xjgA$v_KmL+cZ{sM)2e08Qx+2_AP z=StwdKtSD?D+8{RX0U$c`H!8*b1$@Pc7@WgwpsLn+4F&u3sRZT!epibzstK%ihjd; zD{y|}MUd+u`_-Tg`kL;2>g7x#v)K#UFZV5oZ`LsmG5Q|T=Z3VSD--EUM>b?{Gsn+w9(U$Q__e18^S<6h9R63xQPZwb zBQfx%b`$5E_B7f782A0(Lqo;1qsTrE#&`0Y1NraG*RkW20qY^hhbt8J>byIG&$kXJ}we)+uKzv8P z$o;h&B_C-W+A2=1&(;{3=IBRHW{psPhDMu+W0KXyX+f0;^7x8tD67<(CTlX!Oc@xgqgHR&<`Ta+>Y^WU*;^v#z4 zH$gYx|C_xM{95cY+O5QS@>(T()N@qQ>#l0|EX;x994ZPsO(DlQP_zzm)jZs@tS#Oz zE>ZasOTYWCIMnw#i=F1@BZ+`!i7d70%<<3g`waus%hpRAv+Aknx*$f8yu4 z%j3`FsI$C)?}af>SF8H$(dAHr6JwbhVK?$R~^ z${Fs@&R6rX#v*UwmwQ=+L*W1V^wlc=9>7GI>~C!oI>vqMzkO8ao*2L{V*>tbqRuH0 zF4R%t8a5`Y&SSGDj=&@M*!mgoCXG1M7qpvl0sBB7_Xs#|gHCX2z&UUZVcv%)tYI{`LHbNDI0};5-*mRoE7{I9))Xc>W%z;B6AN0+!4|uk*>zqX2u%6TTe^9US^q|u;&A%2l*TMzYBIa7eTnn2y z8kYS;27ugSV13$0wa*V>eO`g=c?>f1IlGK(kx0t^LNcBlrN>i#rLEM@+dzMUyD;z2 z<-L0DEpkl7U(Ds4P!@e*uABA#KEUbXqjg)_woiH4!n_lf-vt=vUghaxrAtk$bg6ld zxVIm)h`7PAaNOL#W(~~j{R8=lMh+(I9m2f7QBg5WD=CZG1#m#$4DvwRqKw}OT<`RL zi8d}Y>lQhe>vmXll|C8cGv4n?LC^5)iaOHj#W~Vh-#+I1;uNOgLg2dEtUCk|3Kc)iAOz?JmV=*OmigG zrPJF{Fu&|;mziJA?Z4r>6=qM0GWEM=VBOJ967SI-%eCkJ4rv8w!ukh0Pvn#M{|Io9 z{?q5NbFLyC>GYnHcmhpF`WK!6Y;<~8UPCz5dx3NCjh_|k@n#olI)nZm;~KBT zczs`nRb%>2{dSr0N%+Y9jC~oI2ij!<>4n*FI%(!%8ReGJkR@@~Ir=)#XYWrNnS=Zg zXn#m_L&`q%H>$$-@MeHkm9oXNtgSv*m)^jw>aIAZGOk~f4E2($m3{Z+ z4z912==2I{1nbcyK&SUydN@Nm(euv38Qb3Em8CnqxVv5N2Qmf+y3V9nY6|6l$`sY9 zfjsG;yBAZ;k=9`3hcc!X5JX7a8z;}pW`^V79 z9`h~2cpx>P_qt4*n4^6q20mI0T##2J@lMjxI_VqR2l98JA7RiJzaON}{(F?G5_rDW zJb!Gv9@B>-3jF>n^g)&};hjhk{%4=6@qC4O{s^9zT)~iU@SNw{n*0H_dn%^TYA`vJ&O&67c$PBAKnMOJ+O9jC-Ad_fo)d68)v@b0_9t zHOBf)oA?X9#GDk?8m|whKsS8dk6yGrXHg!M{u?Lbwh_}hg= zw%6-#Vf}r0T#f#}@#~qY>y-k0L%Y#9_1x=e$JPyD2 zSUvxFoO7Q9dQAT(%=NSIOS^U<5lRIBNfMrb@m#bA---$CJLM#>_)U0eyYwzR~m*^kH8m zXbR&Y>c~6n#w_b()L0tV$?HFOawz{<(8Z!*IQWX_Xq2fZ>hl?-H_V$F1P?THBI3_2 z+p)*cXP=I^W*np?oLkPZKfgU=#<8OSSN`R`0g)RzPBUM>Ez-QIRLQl{)p6?T9bQeG zwMW~1oknQiix`_Pe>f&@^u%$h@LI2rYenGcq{Sv)M4l&K;C+E1tkZu_)$0^}PlZ}` z1ibIai2TAak)E>ue10NuhkO(hn=i4ozb^B_Q&0iwx~~@br3k;ImGoWr>0s?Nm9LexZytuBU4ujU`32W%3eE*5p=0^~ zQ}?kg$UXLo?BKS6{Qnv~$HAN?U)OL#cp=xJ0Ky-r@n3qcG){x!iSXy>todB*4aj>+2Hm$}uJ8ZyplMaBMTwkjD)P--?xufOi)no8}WdWVPXq%?60ma31|8?uCA{(OX_Q z+hvW$sh3$r;cT zq(rA5=PY;WLr`J(RH2=i@@teaidd`4bca_SU|jSRS=Ur(yZ2J}K>moLFHJn_Ds^2r z-I5L4-ABiMGoW)`7T1NO{z2wBy!S)uzhj>bU!UQALICX@WP7KyHP;QweO;S_IYaD= zM_`~?v33=B-L&oA_wkJe;$Ff1AK?Dqg4?|}rf&DXjr-qK-0zO_`gIEHwW7L0zO`aL zzg6J|V}!-|*|U_+RelkkUkMITiNpWx#?ff@6dOu4A;t_H+>e@LQ2=- zi{ct>FQ39Sw?H1g18uw!&}~rOzXkViH++pTEfdbs`UGt#FW|W)xPKLCm&16N@h;orOoizi`y!=)rLe2lI1$hWEzoU2z;M z0^7yjT?Ux0#&R)rA$|bdvoyoGCWUOe7t~WkY1MX*)-ecHRHy`wbvSn8IEG`+g^>Gkq;MR( zQ1gSM7i!)cd7s{cB+a0mQ`hm)zdjA2u19<9WYvDmGI@3;tE4;+eK$k7hc;8nmL(^cC`R%JAD)Pu4zw+{GjMvu9}j5(>t9G}Kq zqor3*PG--t^w`kP8NXG@>;!9A)-I;+WjvS^J!Oy6Hhp)z(Tul|cDrM~K6@|5UiWss zo0vuzFWn9Kp~umFJS9q9z<%T>Yx}$3k3RE1Z3Fxc?b+{Eg?)ogetkjT5+i-9Gkv4o z>(l6)FVDs2GQL#mAC=x}?CO-ue()C0EG>BECuWSy7gZaVnwJ^MWZduKm=+eSIoD6i zioeYGV|{$fZ#S+5YMQdUjod;w@^$JXSX0`&YmE72d1&=nt}u{!2DtzYTP=O>*-8-t^m&d^3x3#0UD*_dp(kuD5Tuqv0O%^7(=ezDz?8PA~4n{iHhTO#w( z?(G0?;=Kgpx(!}*O;W?_IYa8O9TGaiHT~3g2J&2E?GMD*!;$_{Zt>%euSY-Q!440T zl;`@lerG`XSc5*&CwhlNTT#6?>_Zgiymxvfb)DY4M7!87$H>(8d>{b3f78!;Q0=xV|tU5nu6b=2>K9on$!;J zR*Wq&`%gO@9n-(VPM*8d(R*<_9f>;-IgdEEGm-T8-qV1!zwXkpGolI3syQIG)uPjqL9N-t%E&izm;X2cG?3y9VSM z?brVGD6Vt;Ev*08{S_Z(Y7ERggYW)g*XWvbq=7-BKPKYTWk zUgK>#OXcS{^grvAF-ZQ3xy`bdSbDr|*lzhI=KeVxZ{Ua?pQ#8dj*(N=_}Lbt>l{7x4PWZScz-DEtos%-M*a7xxQ@6K>rt<#_V{b zkI~OCg>N6h@rF4L6rA&3_n7uNOnYUJ^~J7?Ht!ts3~gH((AUJ6>y%0U6W0r2ne=+0 z-zIbi+S)Cw=R4j4em)}C^&W|1aE$Y*9LV4}R^!--jq2vMc?&IVFRYtOd*Mdu zGwJJY%i``4|)HRkeA;B~7=Q=KNkjc(A&r3t;y_kpvt%w17cp$cg@ZHOw-=`D3e z)2@X^Hr<5&EOmzS8O-3`$8y7&Si%a`>t- z-%Xe~xf9=QcnIHCBXNAY4LwJ{0}>mhBM z^KpAsRmCta>-ej7@Aik@njUU?Xh8DnO3tsuX7IdCUh;nSee1A1f2Y_LUd~j2{w$Dr z(|Qo|F|NY-s@NLVgv*?R|F6Th?sC^;E2YN!{$rEX_m26$%n3u=Sm))C>j4MhSQF-H z4d@lHfY8 zeLe3XO;i1MD)G*J|F1c_3i?l7Q0F^Z1sbWwbsq~k2{&YIah1I*tL;bhV{AEAd{%Sz zR{BF*o%p}?Sios_RcuGLRMj8z_rUHD+P}7lbljgG?$eM?)3=6u2J~mSFsky$uYK%T zHRk;b>dstg{aO#>Dy6RD``}Qf<1@3O8opYvraN&Q`s2ucnQyQ6_wl4Yl(CgEcAYYM z3wXow%jqAsEF*AbbN;)9F0j5l?Uk#Xg;|wu@xtjA@t-1GbMItc0sPWmjrQiBZXU?r zWb`!Za@6xBt^oZ_7<~NmMBV3f0UQ!1Eb)m<hJ6jWxg1)-unIs*M7hp|rLi z@2G0<;_0Nf68G;O9Lg8U*rergjCuKUv)!TR4(4d^2=_m05dSv9z8kOI+a|AyM`7W97RX6ALH`Wb5%-z_AN2cP z>$Q9_=^e+sT@9F10YE^|Rz81=%&kxxXU%chj|k*tg(GTFmQDk1Ms$Kez4i^~T$eos z87a@ zuG9C?-u|l5?d;(m&}QzZ>vkAh!?l@$-wD3I2--Uu(SG56TfFvx3HloKyt;tNiLjZp zRk!8mDdqF6_;##nG<}Z+w127Eto1#sftFjrLlSGe+PRvSHE{0D zxuR~5Hlz68x-#jl!5WKNAc7~tpt<|T$_YK$C4|HU5Q5n<}9#VY?C zo@Ff1mvK&bqMYI7$r z-wW=qvKz9b8LOa&hZBun2d?#6S7cktlLF6w9vZsffgfXy0^E-n4TIb}>?-dNouPM= z=2x5_`YDV53gD|2$2uInIFA0$Omz&u^}o}y>6@IwqeQzlHW3Ad;sgWq7PfW z(mGx9LUMefZ((%(eO4xrEhC8P>4$>oSs-EkQpqX6ont zMe!9b<5sRw^x3?DxOiDn{L}80O6P^1*y@I^lXJ=EH-ouil$L#qc|N}Gb~hAncF(;O z-)vat7Tui6oO?6-)8+ZKmRM8Q#(aOZOvkS%wa)7s8Y&ihmfa<=B<XOuEOhFds$B|2tPLc+dGNP<&&K?*y((&3?;w zRF}8%R>(fB_n_S+v@eXBBYrQ9CI4^&$@Q32xy2c5#R55Lx_lTL$yKou4)X z+DOjASXP^yjB~g@%REfB&NX8hdPyCTF#S{D0&DTG4iE8F!)RJy)Gmb4a1&!D415yy zb-sWSrR#=vpe1aB!2vl5C0rULb2$)U9W1y3}2W;CsKd$?sqGiqbE89Zyl~5{cz&tjNh**thW|tjSbyj zhjt%#19LP;93J=0&O3nbKL?s}uq87Gzsx<W*NC_Y?H33%>{Oo5C+??31w*VsoKvKsreHpP%0DF+L>{+vr8z4FY%68H!>_mwv<4 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