From: John Crispin Date: Sat, 3 May 2008 15:51:16 +0000 (+0000) Subject: bump etrax to .25 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=4e7ea16048bde2f02e566c0bd0db70b69d0271fd;p=openwrt%2Fstaging%2Frobimarko.git bump etrax to .25 SVN-Revision: 11028 --- diff --git a/target/linux/etrax/Makefile b/target/linux/etrax/Makefile index cba93cf8ea..2ac747cd0d 100644 --- a/target/linux/etrax/Makefile +++ b/target/linux/etrax/Makefile @@ -10,7 +10,7 @@ ARCH:=cris BOARD:=etrax BOARDNAME:=Foxboard (ETRAX 100LX) FEATURES:=squashfs jffs2 broken -LINUX_VERSION:=2.6.19.2 +LINUX_VERSION:=2.6.25 include $(INCLUDE_DIR)/target.mk @@ -21,19 +21,6 @@ define Target/Description Build fimware images for the FOXBOARD made by acmesystems.it endef -define Kernel/Prepare/Fox - bzcat $(DL_DIR)/$(LINUX_SOURCE) | tar -C $(KERNEL_BUILD_DIR) $(TAR_OPTIONS) - if [ -d ./files ]; then $(CP) ./files/* $(LINUX_DIR)/; fi - if [ -d ./patches/generic_2.6 ]; then $(PATCH) $(LINUX_DIR) ./patches/generic_2.6; fi - if [ -d ./patches/cris ]; then $(PATCH) $(LINUX_DIR) ./patches/cris; fi - ln -sf $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/include/asm-cris/arch-v10 $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/include/asm-cris/arch - ln -sf $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/arch/cris/arch-v10 $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/arch/cris/arch -endef - -define Kernel/Prepare - $(call Kernel/Prepare/Fox) -endef - $(eval $(call BuildTarget)) $(eval $(call RequireCommand,/usr/local/cris/gcc-cris, \ Please install the binary cris toolchain. \ diff --git a/target/linux/etrax/config-default b/target/linux/etrax/config-default index 8a5760ee41..756a89d1b6 100644 --- a/target/linux/etrax/config-default +++ b/target/linux/etrax/config-default @@ -1,16 +1,25 @@ +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_BASE_SMALL=0 -CONFIG_BLK_DEV_SD=y +CONFIG_BITREVERSE=y +CONFIG_BOUNCE=y +CONFIG_CLASSIC_RCU=y CONFIG_CRIS=y +# CONFIG_CRIS_MACH_ARTPEC3 is not set +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_MANAGER=y # CONFIG_ETRAX100LX is not set CONFIG_ETRAX100LX_V2=y # CONFIG_ETRAXFS is not set -# CONFIG_ETRAXFS_SIM is not set CONFIG_ETRAX_ARCH_V10=y # CONFIG_ETRAX_ARCH_V32 is not set CONFIG_ETRAX_AXISFLASHMAP=y -# CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE is not set CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock1 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd console=ttyS0,115200" # CONFIG_ETRAX_CSP0_LEDS is not set # CONFIG_ETRAX_DEBUG_PORT0 is not set @@ -19,7 +28,6 @@ CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock1 rootfstype=squashfs,jffs2 init=/etc/pr # CONFIG_ETRAX_DEBUG_PORT3 is not set CONFIG_ETRAX_DEBUG_PORT_NULL=y CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x4 -# CONFIG_ETRAX_DEF_R_PORT_G_DIR is not set CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0xf0 CONFIG_ETRAX_DEF_R_PORT_PA_DIR=0x1c CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=0x00 @@ -46,7 +54,7 @@ CONFIG_ETRAX_I2C_CLK_PORT=1 CONFIG_ETRAX_I2C_DATA_PORT=0 # CONFIG_ETRAX_I2C_EEPROM is not set CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y -# CONFIG_ETRAX_IDE is not set +# CONFIG_ETRAX_KMALLOCED_MODULES is not set CONFIG_ETRAX_LED1G=2 CONFIG_ETRAX_LED1R=2 CONFIG_ETRAX_LED2G=3 @@ -57,7 +65,7 @@ CONFIG_ETRAX_NANDFLASH_BUSWIDTH=1 CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set # CONFIG_ETRAX_NO_LEDS is not set -# CONFIG_ETRAX_NO_PHY is not set +CONFIG_ETRAX_PA_BUTTON_BITMASK=02 CONFIG_ETRAX_PA_CHANGEABLE_BITS=0xFF CONFIG_ETRAX_PA_CHANGEABLE_DIR=0xFF CONFIG_ETRAX_PA_LEDS=y @@ -113,6 +121,8 @@ CONFIG_ETRAX_SERIAL=y # CONFIG_ETRAX_SERIAL_FAST_TIMER is not set # CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is not set CONFIG_ETRAX_SERIAL_PORT0=y +# CONFIG_ETRAX_SERIAL_PORT0_DMA0_OUT is not set +# CONFIG_ETRAX_SERIAL_PORT0_DMA1_IN is not set # CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT is not set # CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN is not set CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN=y @@ -121,28 +131,46 @@ CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT=y CONFIG_ETRAX_SERIAL_PORT2=y CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y +# CONFIG_ETRAX_SERIAL_PORT2_DMA6_OUT is not set +# CONFIG_ETRAX_SERIAL_PORT2_DMA7_IN is not set # CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set # CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set CONFIG_ETRAX_SERIAL_PORT3=y +# CONFIG_ETRAX_SERIAL_PORT3_DMA2_OUT is not set +# CONFIG_ETRAX_SERIAL_PORT3_DMA3_IN is not set CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT=y CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN=y +# CONFIG_ETRAX_SERIAL_PORT3_DMA8_OUT is not set +# CONFIG_ETRAX_SERIAL_PORT3_DMA9_IN is not set # CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN is not set # CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT is not set CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS=1 # CONFIG_ETRAX_SOFT_SHUTDOWN is not set # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set -CONFIG_ETRAX_SYSFS_NODES=y CONFIG_ETRAX_USB_HOST=y CONFIG_ETRAX_USB_HOST_PORT1=y CONFIG_ETRAX_USB_HOST_PORT2=y +# CONFIG_ETRAX_VCS_SIM is not set # CONFIG_ETRAX_WATCHDOG is not set CONFIG_FAT_FS=y +CONFIG_FORCE_MAX_ZONEORDER=6 CONFIG_FS_POSIX_ACL=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_IOMAP=y # CONFIG_GEN_RTC is not set +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAVE_IDE=y +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_HAVE_OPROFILE is not set # CONFIG_HOSTAP is not set # CONFIG_HW_RANDOM is not set +# CONFIG_I2C is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set # CONFIG_IDE is not set CONFIG_IEEE80211=y # CONFIG_IEEE80211_CRYPT_CCMP is not set @@ -152,13 +180,15 @@ CONFIG_IEEE80211_DEBUG=y CONFIG_IEEE80211_SOFTMAC=y CONFIG_IEEE80211_SOFTMAC_DEBUG=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_IRQ_PER_CPU=y +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m CONFIG_MSDOS_FS=y CONFIG_MTD=y CONFIG_MTDRAM_ABS_POS=0x0 CONFIG_MTDRAM_ERASE_SIZE=128 CONFIG_MTDRAM_TOTAL_SIZE=0 # CONFIG_MTD_ABSENT is not set +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y # CONFIG_MTD_BLOCK2MTD is not set CONFIG_MTD_CFI=y @@ -192,7 +222,6 @@ 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_MTDRAM=y -# CONFIG_MTD_OBSOLETE_CHIPS is not set # CONFIG_MTD_ONENAND is not set # CONFIG_MTD_OTP is not set CONFIG_MTD_PARTITIONS=y @@ -203,33 +232,27 @@ CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_REDBOOT_PARTS is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_SLRAM is not set -CONFIG_MTD_SPLIT_ROOTFS=y -# CONFIG_NET_WIRELESS_RTNETLINK is not set CONFIG_NLS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y +CONFIG_NO_IOPORT=y # CONFIG_OOM_REBOOT is not set -# CONFIG_OVERRIDE_SCHED_STARVATION_LIMIT is not set # CONFIG_RTC is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_SCSI=y # CONFIG_SERIAL_8250 is not set -# CONFIG_SMP is not set -# CONFIG_SOFT_WATCHDOG is not set +CONFIG_SLABINFO=y # CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set # CONFIG_SVINTO_SIM is not set # CONFIG_SYSTEM_PROFILER is not set +CONFIG_SYSVIPC_SYSCTL=y CONFIG_UID16=y -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_UNWIND_INFO is not set CONFIG_USB=y -# CONFIG_USBPCWATCHDOG is not set # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_R8A66597_HCD is not set # CONFIG_USB_SERIAL_IR is not set -CONFIG_USB_STORAGE=y CONFIG_USB_ZD1201=y CONFIG_VFAT_FS=y # CONFIG_VLAN_8021Q is not set -# CONFIG_ZD1211RW is not set diff --git a/target/linux/etrax/files/arch/cris/arch-v10/drivers/gpio_syscalls.c b/target/linux/etrax/files/arch/cris/arch-v10/drivers/gpio_syscalls.c deleted file mode 100644 index b6300aa9cd..0000000000 --- a/target/linux/etrax/files/arch/cris/arch-v10/drivers/gpio_syscalls.c +++ /dev/null @@ -1,191 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - - -extern int errno; - - -asmlinkage void sys_gpiosetbits(unsigned char port, unsigned int bits){ - switch(port){ - case 'G': - case 'g': - *R_PORT_G_DATA = port_g_data_shadow |= bits; - break; - - case 'A': - case 'a': - *R_PORT_PA_DATA = port_pa_data_shadow |= bits; - break; - - case 'B': - case 'b': - *R_PORT_PB_DATA = port_pb_data_shadow |= bits; - break; - - }; -}; - - -asmlinkage void sys_gpioclearbits(unsigned char port, unsigned int bits){ - switch(port){ - case 'G': - case 'g': - *R_PORT_G_DATA = port_g_data_shadow &= ~bits; - break; - - case 'A': - case 'a': - *R_PORT_PA_DATA = port_pa_data_shadow &= ~bits; - break; - - case 'B': - case 'b': - *R_PORT_PB_DATA = port_pb_data_shadow &= ~bits; - break; - - }; -}; - -asmlinkage void sys_gpiosetdir(unsigned char port, unsigned char dir, unsigned int bits){ - if((dir=='I' )||(dir=='i')){ - switch(port){ - case 'G': - case 'g': - if(bits & (1<<0)){ - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g0dir); - }; - if((bits & 0x0000FF00)==0x0000FF00){ - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g8_15dir); - }; - if((bits & 0x00FF0000)==0x00FF0000){ - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g16_23dir); - }; - if(bits & (1<<24)){ - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g24dir); - }; - *R_GEN_CONFIG = genconfig_shadow; - break; - - case 'A': - case 'a': - *R_PORT_PA_DIR = port_pa_dir_shadow &= ~(bits & 0xff); - break; - - case 'B': - case 'b': - *R_PORT_PB_DIR = port_pb_dir_shadow &= ~(bits & 0xff); - break; - }; - } else if((dir=='O' )||(dir=='o')){ - switch(port){ - case 'G': - case 'g': - if(bits & (1<<0)){ - genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g0dir); - }; - if((bits & 0x0000FF00)==0x0000FF00){ - genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g8_15dir); - }; - if((bits & 0x00FF0000)==0x00FF0000){ - genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g8_15dir); - }; - if(bits & (1<<24)){ - genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g24dir); - }; - *R_GEN_CONFIG = genconfig_shadow; - break; - - case 'A': - case 'a': - *R_PORT_PA_DIR = port_pa_dir_shadow |= (bits & 0xff); - break; - - case 'B': - case 'b': - *R_PORT_PB_DIR = port_pb_dir_shadow |= (bits & 0xff); - break; - }; - }; -}; - - -asmlinkage void sys_gpiotogglebit(unsigned char port, unsigned int bits){ - switch(port){ - case 'G': - case 'g': - if(port_g_data_shadow & bits){ - *R_PORT_G_DATA = port_g_data_shadow &= ~bits; - } else { - *R_PORT_G_DATA = port_g_data_shadow |= bits; - }; - break; - - case 'A': - case 'a': - if(*R_PORT_PA_DATA & bits){ - *R_PORT_PA_DATA = port_pa_data_shadow &= ~(bits & 0xff); - } else { - *R_PORT_PA_DATA = port_pa_data_shadow |= (bits & 0xff); - }; - break; - - case 'B': - case 'b': - if(*R_PORT_PB_DATA & bits){ - *R_PORT_PB_DATA = port_pb_data_shadow &= ~(bits & 0xff); - } else { - *R_PORT_PB_DATA = port_pb_data_shadow |= (bits & 0xff); - }; - break; - - }; -}; - - -asmlinkage unsigned int sys_gpiogetbits(unsigned char port, unsigned int bits){ - unsigned int data = 0; - switch(port){ - case 'G': - case 'g': - data = *R_PORT_G_DATA; - break; - - case 'A': - case 'a': - data = *R_PORT_PA_DATA; - break; - - case 'B': - case 'b': - data = *R_PORT_PB_DATA; - break; - - }; - data &= bits; - return data; -}; - - diff --git a/target/linux/etrax/files/drivers/spi/spi_crisv32_gpio.c b/target/linux/etrax/files/drivers/spi/spi_crisv32_gpio.c deleted file mode 100644 index e31f6fc281..0000000000 --- a/target/linux/etrax/files/drivers/spi/spi_crisv32_gpio.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Simple bitbanged-GPIO SPI driver for ETRAX FS et al. - * - * Copyright (c) 2007 Axis Communications AB - * - * Author: Hans-Peter Nilsson, inspired by earlier work by - * Andre Spanberg but mostly by copying large parts of - * spi_s3c24xx_gpio.c, hence also: - * Copyright (c) 2006 Ben Dooks - * Copyright (c) 2006 Simtec Electronics - * - * 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 - -/* Our main driver state. */ - -struct crisv32_spi_hw_info { - struct crisv32_iopin sclk; - struct crisv32_iopin mosi; - struct crisv32_iopin miso; - struct crisv32_iopin cs; -}; - -/* - * The driver state hides behind the spi_bitbang state. We're - * responsible for allocating that, so we can get a little something - * for ourselves. - */ - -struct crisv32_spi_gpio_devdata { - struct spi_bitbang bitbang; - struct crisv32_spi_hw_info pins; -}; - -/* Helper function getting the driver state from a spi_device. */ - -static inline struct crisv32_spi_hw_info *spidev_to_hw(struct spi_device *spi) -{ - struct crisv32_spi_gpio_devdata *dd = spi_master_get_devdata(spi->master); - return &dd->pins; -} - -/* The SPI-bitbang functions: see spi_bitbang.h at EXPAND_BITBANG_TXRX. */ - -static inline void setsck(struct spi_device *spi, int is_on) -{ - crisv32_io_set(&spidev_to_hw(spi)->sclk, is_on != 0); -} - -static inline void setmosi(struct spi_device *spi, int is_on) -{ - crisv32_io_set(&spidev_to_hw(spi)->mosi, is_on != 0); -} - -static inline u32 getmiso(struct spi_device *spi) -{ - return crisv32_io_rd(&spidev_to_hw(spi)->miso) != 0 ? 1 : 0; -} - -#define spidelay(x) ndelay(x) - -#define EXPAND_BITBANG_TXRX -#include - -/* - * SPI-bitbang word transmit-functions for the four SPI modes, - * dispatching to the inlined functions we just included. - */ - -static u32 crisv32_spi_gpio_txrx_mode0(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); -} - -static u32 crisv32_spi_gpio_txrx_mode1(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); -} - -static u32 crisv32_spi_gpio_txrx_mode2(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); -} - -static u32 crisv32_spi_gpio_txrx_mode3(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); -} - -/* SPI-bitbang chip-select function. */ - -static void crisv32_spi_gpio_chipselect(struct spi_device *spi, int value) -{ - if (spi->mode & SPI_CS_HIGH) - crisv32_io_set(&spidev_to_hw(spi)->cs, - value == BITBANG_CS_ACTIVE ? 1 : 0); - else - crisv32_io_set(&spidev_to_hw(spi)->cs, - value == BITBANG_CS_ACTIVE ? 0 : 1); -} - -/* Platform-device probe function. */ - -static int __devinit crisv32_spi_gpio_probe(struct platform_device *dev) -{ - struct spi_master *master; - struct crisv32_spi_gpio_devdata *dd; - struct resource *res; - struct crisv32_spi_gpio_controller_data *gc; - int ret = 0; - - /* - * We need to get the controller data as a hardware resource, - * or else it wouldn't be available until *after* the - * spi_bitbang_start call! - */ - res = platform_get_resource_byname(dev, 0, "controller_data_ptr"); - if (res == NULL) { - dev_err(&dev->dev, "can't get controller_data resource\n"); - return -EIO; - } - - gc = (struct crisv32_spi_gpio_controller_data *) res->start; - - master = spi_alloc_master(&dev->dev, sizeof *dd); - if (master == NULL) { - dev_err(&dev->dev, "failed to allocate spi master\n"); - ret = -ENOMEM; - goto err; - } - - dd = spi_master_get_devdata(master); - platform_set_drvdata(dev, dd); - - /* - * The device data asks for this driver, and holds the id - * number, which must be unique among the same-type devices. - * We use this as the number of this SPI bus. - */ - master->bus_num = dev->id; - - /* - * Allocate pins. Note that thus being allocated as GPIO, we - * don't have to deconfigure them at the end or if something - * fails. - */ - if ((ret = crisv32_io_get_name(&dd->pins.cs, gc->cs)) != 0 - || (ret = crisv32_io_get_name(&dd->pins.miso, gc->miso)) != 0 - || (ret = crisv32_io_get_name(&dd->pins.mosi, gc->mosi)) != 0 - || (ret = crisv32_io_get_name(&dd->pins.sclk, gc->sclk)) != 0) - goto err_no_pins; - - /* Set directions of the SPI pins. */ - crisv32_io_set_dir(&dd->pins.cs, crisv32_io_dir_out); - crisv32_io_set_dir(&dd->pins.sclk, crisv32_io_dir_out); - crisv32_io_set_dir(&dd->pins.miso, crisv32_io_dir_in); - crisv32_io_set_dir(&dd->pins.mosi, crisv32_io_dir_out); - - /* Set state of the SPI pins. */ - dev_dbg(&dev->dev, "cs.port 0x%x, pin: %d\n" - dd->pins.cs.port, dd->pins.cs.bit); - - /* - * Can't use crisv32_spi_gpio_chipselect(spi, 1) here; we - * don't have a proper "spi" until after spi_bitbang_start. - */ - crisv32_io_set(&dd->pins.cs, 1); - crisv32_io_set(&dd->pins.sclk, 0); - crisv32_io_set(&dd->pins.mosi, 0); - - /* Setup SPI bitbang adapter hooks. */ - dd->bitbang.master = spi_master_get(master); - dd->bitbang.chipselect = crisv32_spi_gpio_chipselect; - - dd->bitbang.txrx_word[SPI_MODE_0] = crisv32_spi_gpio_txrx_mode0; - dd->bitbang.txrx_word[SPI_MODE_1] = crisv32_spi_gpio_txrx_mode1; - dd->bitbang.txrx_word[SPI_MODE_2] = crisv32_spi_gpio_txrx_mode2; - dd->bitbang.txrx_word[SPI_MODE_3] = crisv32_spi_gpio_txrx_mode3; - - ret = spi_bitbang_start(&dd->bitbang); - if (ret) - goto err_no_bitbang; - - printk (KERN_INFO "CRIS v32 SPI driver for GPIO" - " (cs: %s, miso: %s, mosi: %s, sclk: %s)\n", - gc->cs, gc->miso, gc->mosi, gc->sclk); - - return 0; - - err_no_bitbang: - spi_master_put(dd->bitbang.master); - err_no_pins: - platform_set_drvdata(dev, NULL); - err: - return ret; -} - -/* Platform-device remove-function. */ - -static int __devexit crisv32_spi_gpio_remove(struct platform_device *dev) -{ - struct crisv32_spi_gpio_devdata *dd = platform_get_drvdata(dev); - int ret; - - ret = spi_bitbang_stop(&dd->bitbang); - if (ret != 0) - return ret; - - spi_master_put(dd->bitbang.master); - platform_set_drvdata(dev, NULL); - return 0; -} - -/* - * For the time being, there's no suspend/resume support to care - * about, so we let those handlers default to NULL. - */ -static struct platform_driver crisv32_spi_gpio_drv = { - .probe = crisv32_spi_gpio_probe, - .remove = __devexit_p(crisv32_spi_gpio_remove), - .driver = { - .name = "spi_crisv32_gpio", - .owner = THIS_MODULE, - }, -}; - -/* Module init function. */ - -static int __devinit crisv32_spi_gpio_init(void) -{ - return platform_driver_register(&crisv32_spi_gpio_drv); -} - -/* Module exit function. */ - -static void __devexit crisv32_spi_gpio_exit(void) -{ - platform_driver_unregister(&crisv32_spi_gpio_drv); -} - -module_init(crisv32_spi_gpio_init); -module_exit(crisv32_spi_gpio_exit); - -MODULE_DESCRIPTION("CRIS v32 SPI-GPIO Driver"); -MODULE_AUTHOR("Hans-Peter Nilsson, "); -MODULE_LICENSE("GPL"); diff --git a/target/linux/etrax/files/drivers/spi/spi_crisv32_sser.c b/target/linux/etrax/files/drivers/spi/spi_crisv32_sser.c deleted file mode 100644 index e8d0e4973b..0000000000 --- a/target/linux/etrax/files/drivers/spi/spi_crisv32_sser.c +++ /dev/null @@ -1,1566 +0,0 @@ -/* - * SPI port driver for ETRAX FS et al. using a synchronous serial - * port, but simplified by using the spi_bitbang framework. - * - * Copyright (c) 2007 Axis Communications AB - * - * Author: Hans-Peter Nilsson, though copying parts of - * spi_s3c24xx_gpio.c, hence also: - * Copyright (c) 2006 Ben Dooks - * Copyright (c) 2006 Simtec Electronics - * - * 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 driver restricts frequency, polarity, "word" length and endian - * much more than the hardware does. I'm happy to unrestrict it, but - * only with what I can test myself (at time of writing, just SD/MMC - * SPI) and what people actually test and report. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* A size "not much larger" than the max typical transfer size. */ -#define DMA_CHUNKSIZ 512 - -/* - * For a transfer expected to take this long, we busy-wait instead of enabling - * interrupts. - */ -#define IRQ_USAGE_THRESHOLD_NS 14000 - -/* A few register access macros to avoid verbiage and reduce typos. */ -#define REG_RD_DI(reg) REG_RD(dma, regi_dmain, reg) -#define REG_RD_DO(reg) REG_RD(dma, regi_dmaout, reg) -#define REG_RD_SSER(reg) REG_RD(sser, regi_sser, reg) -#define REG_WR_DI(reg, val) REG_WR(dma, regi_dmain, reg, val) -#define REG_WR_DO(reg, val) REG_WR(dma, regi_dmaout, reg, val) -#define REG_WR_SSER(reg, val) REG_WR(sser, regi_sser, reg, val) -#define REG_WRINT_DI(reg, val) REG_WR_INT(dma, regi_dmain, reg, val) -#define REG_WRINT_DO(reg, val) REG_WR_INT(dma, regi_dmaout, reg, val) -#define REG_WRINT_SSER(reg, val) REG_WR_INT(sser, regi_sser, reg, val) -#define REG_RDINT_DI(reg) REG_RD_INT(dma, regi_dmain, reg) -#define REG_RDINT_DO(reg) REG_RD_INT(dma, regi_dmaout, reg) -#define REG_RDINT_SSER(reg) REG_RD_INT(sser, regi_sser, reg) - -#define DMA_WAIT_UNTIL_RESET(inst) \ - do { \ - reg_dma_rw_stat r; \ - do { \ - r = REG_RD(dma, (inst), rw_stat); \ - } while (r.mode != regk_dma_rst); \ - } while (0) - -#define DMA_BUSY(inst) (REG_RD(dma, inst, rw_stream_cmd)).busy - -/* Our main driver state. */ -struct crisv32_spi_hw_info { - struct crisv32_regi_n_int sser; - struct crisv32_regi_n_int dmain; - struct crisv32_regi_n_int dmaout; - - reg_sser_rw_cfg cfg; - reg_sser_rw_frm_cfg frm_cfg; - reg_sser_rw_tr_cfg tr_cfg; - reg_sser_rw_rec_cfg rec_cfg; - reg_sser_rw_extra extra; - - /* We store the speed in kHz, so we can have expressions - * multiplying 100MHz by * 4 before dividing by it, and still - * keep it in an u32. */ - u32 effective_speed_kHz; - - /* - * The time in 10s of nanoseconds for half a cycles. - * For convenience and performance; derived from the above. - */ - u32 half_cycle_delay_ns; - - /* This should be overridable by a module parameter. */ - u32 max_speed_Hz; - - /* Pre-computed timout for the max transfer chunk-size. */ - u32 dma_timeout; - - struct completion dma_done; - - /* - * If we get a timeout from wait_for_completion_timeout on the - * above, first look at this before panicking. - */ - u32 dma_actually_done; - - /* - * Resources don't seem available at the remove call, so we - * have to save information we get through them. - */ - struct crisv32_spi_sser_controller_data *gc; -}; - -/* - * The driver state hides behind the spi_bitbang state; we're - * responsible for allocating that, so we can get a little something - * for ourselves. - */ -struct crisv32_spi_sser_devdata { - struct spi_bitbang bitbang; - struct crisv32_spi_hw_info hw; -}; - -/* Our DMA descriptors that need alignment. */ -struct crisv32_spi_dma_descrs { - dma_descr_context in_ctxt __attribute__ ((__aligned__(32))); - dma_descr_context out_ctxt __attribute__ ((__aligned__(32))); - - /* - * The code takes advantage of the fact that in_descr and - * out_descr are on the same cache-line when working around - * the cache-bug in TR 106. - */ - dma_descr_data in_descr __attribute__ ((__aligned__(16))); - dma_descr_data out_descr __attribute__ ((__aligned__(16))); -}; - -/* - * Whatever needs DMA access is here, besides whatever DMA-able memory - * comes in transfers. - */ -struct crisv32_spi_dma_cs { - struct crisv32_spi_dma_descrs *descrp; - - /* Scratch-buffers when the original was non-DMA. */ - u8 rx_buf[DMA_CHUNKSIZ]; - u8 tx_buf[DMA_CHUNKSIZ]; -}; - -/* - * Max speed. If set, we won't go faster, promise. May be useful - * when dealing with weak hardware; misrouted signal paths or various - * debug-situations. - */ -static ulong crisv32_spi_speed_limit_Hz = 0; - -/* Helper function getting the driver state from a spi_device. */ - -static inline struct crisv32_spi_hw_info *spidev_to_hw(struct spi_device *spi) -{ - struct crisv32_spi_sser_devdata *dd = spi_master_get_devdata(spi->master); - return &dd->hw; -} - -/* SPI-bitbang word transmit-function for non-DMA. */ - -static u32 crisv32_spi_sser_txrx_mode3(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - u32 regi_sser = hw->sser.regi; - reg_sser_rw_ack_intr ack_intr = { .trdy = 1, .rdav = 1 }; - reg_sser_r_intr intr = {0}; - reg_sser_rw_tr_data w_data = { .data = (u8) word }; - reg_sser_r_rec_data r_data; - u32 i; - - /* - * The timeout reflects one iteration per 10ns (impossible at - * 200MHz clock even without the ndelay) and a wait for a full - * byte. - */ - u32 timeout = 1000000/10*8/hw->effective_speed_kHz; - - BUG_ON(bits != 8); - - intr = REG_RD_SSER(r_intr); - - /* - * We should never get xruns when we control the transmitter - * and receiver in register mode. And if we don't have - * transmitter-ready and data-ready on entry, something's - * seriously fishy. - */ - if (!intr.trdy || !intr.rdav || intr.orun || intr.urun) - panic("sser hardware or SPI driver broken (1) 0x%x\n", - REG_TYPE_CONV(u32, reg_sser_r_intr, intr)); - - REG_WR_SSER(rw_ack_intr, ack_intr); - REG_WR_SSER(rw_tr_data, w_data); - - for (i = 0; i < timeout; i++) { - intr = REG_RD_SSER(r_intr); - /* Wait for received data. */ - if (intr.rdav) - break; - ndelay(10); - } - - if (!(intr.trdy && intr.rdav) || intr.orun || intr.urun) - panic("sser hardware or SPI driver broken (2) 0x%x\n", - REG_TYPE_CONV(u32, reg_sser_r_intr, intr)); - - r_data = REG_RD_SSER(r_rec_data); - return r_data.data & 0xff; -} - -/* - * Wait for 1/2 bit-time if the transmitter or receiver is enabled. - * We need to do this as the data-available indications may arrive - * right at the edge, with half the last cycle remaining. - */ -static void inline crisv32_spi_sser_wait_halfabit(struct crisv32_spi_hw_info - *hw) -{ - if (hw->cfg.en) - ndelay(hw->half_cycle_delay_ns); -} - -/* - * Assert or de-assert chip-select. - * We have two functions, with the active one assigned to the bitbang - * slot at setup, to avoid a performance penalty (1% on reads). - */ -static void crisv32_spi_sser_chip_select_active_high(struct spi_device *spi, - int value) -{ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - u32 regi_sser = hw->sser.regi; - - /* - * We may have received data at the "last producing clock - * edge". Thus we delay for another half a clock cycle. - */ - crisv32_spi_sser_wait_halfabit(hw); - - hw->frm_cfg.frame_pin_use - = value == BITBANG_CS_ACTIVE ? regk_sser_gio1 : regk_sser_gio0; - REG_WR_SSER(rw_frm_cfg, hw->frm_cfg); -} - -static void crisv32_spi_sser_chip_select_active_low(struct spi_device *spi, - int value) -{ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - u32 regi_sser = hw->sser.regi; - - crisv32_spi_sser_wait_halfabit(hw); - hw->frm_cfg.frame_pin_use - = value == BITBANG_CS_ACTIVE ? regk_sser_gio0 : regk_sser_gio1; - REG_WR_SSER(rw_frm_cfg, hw->frm_cfg); -} - -/* Set the transmission speed in Hz. */ - -static int crisv32_spi_sser_set_speed_Hz(struct crisv32_spi_hw_info *hw, - u32 Hz) -{ - u32 kHz; - u32 ns_delay; - u32 regi_sser = hw->sser.regi; - - if (Hz > hw->max_speed_Hz) - /* - * Should we complain? Return error? Current caller - * sequences want just the max speed. - */ - Hz = hw->max_speed_Hz; - - kHz = Hz/1000; - - /* - * If absolutely needed, we *could* change the base frequency - * and go lower. Usually, a frequency set higher than wanted - * is a problem but lower isn't. - */ - if (Hz < 100000000 / 65536 + 1) { - printk(KERN_ERR "attempt to set invalid sser speed: %u Hz\n", - Hz); - Hz = 100000000 / 65536 + 1; - } - - pr_debug("setting sser speed to %u Hz\n", Hz); - - /* - * Avoid going above the requested speed if there's a - * remainder for the 100 MHz clock-divider calculation, but - * don't unnecessarily go below if it's even. - */ - hw->cfg.clk_div = 100000000/Hz - ((100000000 % Hz) == 0); - - /* Make sure there's no ongoing transmission. */ - crisv32_spi_sser_wait_halfabit(hw); - - /* - * Wait for 3 times max of the old and the new clock before and after - * changing the frequency. Not because of documentation or empirical - * need, but because it seems sane to do so. The three-bit-times - * value is because that's the documented time it takes for a reset to - * take effect. - */ - ns_delay = 1000000*3/(kHz > hw->effective_speed_kHz - ? kHz : hw->effective_speed_kHz); - ndelay(ns_delay); - REG_WR_SSER(rw_cfg, hw->cfg); - ndelay(ns_delay); - - hw->effective_speed_kHz = kHz; - - /* - * A timeout of twice the time for the largest chunk (not - * counting DMA overhead) plus one jiffy, should be more than - * enough for the transmission. - */ - hw->dma_timeout = 1 + usecs_to_jiffies(1000*2*DMA_CHUNKSIZ*8/kHz); - - hw->half_cycle_delay_ns - = 1000000/2/hw->effective_speed_kHz; - - pr_debug(".clk_div %d, half %d, eff %d\n", - hw->cfg.clk_div, hw->half_cycle_delay_ns, - hw->effective_speed_kHz); - return 0; -} - -/* - * Set up transmitter and receiver for non-DMA access. - * Unfortunately, it doesn't seem like hispeed works for this mode - * (mea culpa), so we're stuck with lospeed-mode. A little slower, - * but that's what you get for not allocating DMA. - */ -static int crisv32_setup_spi_sser_for_reg_access(struct crisv32_spi_hw_info *hw) -{ - u32 regi_sser = hw->sser.regi; - - reg_sser_rw_cfg cfg = {0}; - reg_sser_rw_frm_cfg frm_cfg = {0}; - reg_sser_rw_tr_cfg tr_cfg = {0}; - reg_sser_rw_rec_cfg rec_cfg = {0}; - reg_sser_rw_intr_mask mask = {0}; - reg_sser_rw_extra extra = {0}; - reg_sser_rw_tr_data tr_data = {0}; - reg_sser_r_intr intr; - - cfg.en = 0; - tr_cfg.tr_en = 1; - rec_cfg.rec_en = 1; - REG_WR_SSER(rw_cfg, cfg); - REG_WR_SSER(rw_tr_cfg, tr_cfg); - REG_WR_SSER(rw_rec_cfg, rec_cfg); - REG_WR_SSER(rw_intr_mask, mask); - - /* - * See 23.7.2 SPI in the hardware documentation. - * Except our configuration uses bulk mode; MMC/SD-SPI - * isn't isochronous in nature. - * Step 1. - */ - cfg.gate_clk = regk_sser_yes; - cfg.clkgate_in = regk_sser_no; - cfg.clkgate_ctrl = regk_sser_tr; - - /* Step 2. */ - cfg.out_clk_pol = regk_sser_pos; - cfg.out_clk_src = regk_sser_intern_clk; - - /* Step 3. */ - tr_cfg.clk_src = regk_sser_intern; - rec_cfg.clk_src = regk_sser_intern; - frm_cfg.clk_src = regk_sser_intern; - - /* Step 4. */ - tr_cfg.clk_pol = regk_sser_neg; - rec_cfg.clk_pol = regk_sser_pos; - frm_cfg.clk_pol = regk_sser_neg; - - /* - * Step 5: frame pin (PC03 or PD03) is frame; the status pin - * (PC02, PD02) is configured as input. - */ - frm_cfg.frame_pin_dir = regk_sser_out; - - /* - * Contrary to the doc example, we don't generate the frame - * signal "automatically". This setting of the frame pin as - * constant 1, reflects an inactive /CS setting, for just idle - * clocking. When we need to transmit or receive data, we - * change it. - */ - frm_cfg.frame_pin_use = regk_sser_gio1; - frm_cfg.status_pin_dir = regk_sser_in; - - /* - * Step 6. This is probably not necessary, as we don't - * generate the frame signal automatically. Nevertheless, - * modified for bulk transmission. - */ - frm_cfg.out_on = regk_sser_tr; - frm_cfg.out_off = regk_sser_tr; - - /* Step 7. Similarly, maybe not necessary. */ - frm_cfg.type = regk_sser_level; - frm_cfg.level = regk_sser_neg_lo; - - /* Step 8. These we have to set according to the bulk mode, - * which for tr_delay is the same as for iso; a value of 1 - * means in sync with the frame signal. For rec_delay, we - * start it at the same time as the transmitter. See figure - * 23.7 in the hw documentation. */ - frm_cfg.tr_delay = 1; - frm_cfg.rec_delay = 0; - - /* Step 9. */ - tr_cfg.sample_size = 7; - rec_cfg.sample_size = 7; - - /* Step 10. */ - frm_cfg.wordrate = 7; - - /* Step 11 (but for bulk). */ - tr_cfg.rate_ctrl = regk_sser_bulk; - - /* - * Step 12. Similarly, maybe not necessary; still, modified - * for bulk. - */ - tr_cfg.frm_src = regk_sser_intern; - rec_cfg.frm_src = regk_sser_tx_bulk; - - /* Step 13. */ - tr_cfg.mode = regk_sser_lospeed; - rec_cfg.mode = regk_sser_lospeed; - - /* Step 14. */ - tr_cfg.sh_dir = regk_sser_msbfirst; - rec_cfg.sh_dir = regk_sser_msbfirst; - - /* - * Extra step for bulk-specific settings and other general - * settings not specified in the SPI config example. - * It's uncertain whether all of these are needed. - */ - tr_cfg.bulk_wspace = 1; - tr_cfg.use_dma = 0; - - tr_cfg.urun_stop = 1; - rec_cfg.orun_stop = 1; - rec_cfg.use_dma = 0; - - rec_cfg.fifo_thr = regk_sser_inf; - frm_cfg.early_wend = regk_sser_yes; - - cfg.clk_dir = regk_sser_out; - tr_cfg.data_pin_use = regk_sser_dout; - cfg.base_freq = regk_sser_f100; - - /* Setup for the initial frequency given to us. */ - hw->cfg = cfg; - crisv32_spi_sser_set_speed_Hz(hw, hw->max_speed_Hz); - cfg = hw->cfg; - - /* - * Write it all, except cfg which is already written by - * crisv32_spi_sser_set_speed_Hz. - */ - REG_WR_SSER(rw_frm_cfg, frm_cfg); - REG_WR_SSER(rw_tr_cfg, tr_cfg); - REG_WR_SSER(rw_rec_cfg, rec_cfg); - REG_WR_SSER(rw_extra, extra); - - /* - * The transmit-register needs to be written before the - * transmitter is enabled, and to get a valid trdy signal - * waiting for us when we want to transmit a byte. Because - * the "frame event" is that the transmitter is written, this - * will cause a dummy 0xff-byte to be transmitted, but that's - * ok, because /CS is inactive. - */ - tr_data.data = 0xffff; - REG_WR_SSER(rw_tr_data, tr_data); - - /* - * We ack everything interrupt-wise; left-over indicators don't have - * to come from *this* code. - */ - REG_WRINT_SSER(rw_ack_intr, -1); - - /* - * Wait 3 cycles before enabling, after the transmit register - * has been written. (This'll be just a few microseconds for - * e.g. 400 KHz.) - */ - ndelay(3 * 2 * hw->half_cycle_delay_ns); - cfg.en = 1; - - REG_WR_SSER(rw_cfg, cfg); - - /* - * Now wait for 8 + 3 cycles. The 0xff byte should now have - * been transmitted and dummy data received. - */ - ndelay((8 + 3) * 2 * hw->half_cycle_delay_ns); - - /* - * Sanity-check that we have data-available and the - * transmitter is ready to send new data. - */ - intr = REG_RD_SSER(r_intr); - if (!intr.rdav || !intr.trdy) - panic("sser hw or SPI driver broken (3) 0x%x", - REG_TYPE_CONV(u32, reg_sser_r_intr, intr)); - - hw->frm_cfg = frm_cfg; - hw->tr_cfg = tr_cfg; - hw->rec_cfg = rec_cfg; - hw->extra = extra; - hw->cfg = cfg; - return 0; -} - -/* Initialization, maybe fault recovery. */ - -static void crisv32_reset_dma_hw(u32 regi) -{ - REG_WR_INT(dma, regi, rw_intr_mask, 0); - - DMA_RESET(regi); - DMA_WAIT_UNTIL_RESET(regi); - DMA_ENABLE(regi); - REG_WR_INT(dma, regi, rw_ack_intr, -1); - - DMA_WR_CMD(regi, regk_dma_set_w_size1); -} - -/* Interrupt from SSER, for use with DMA when only the transmitter is used. */ - -static irqreturn_t sser_interrupt(int irqno, void *arg) -{ - struct crisv32_spi_hw_info *hw = arg; - u32 regi_sser = hw->sser.regi; - reg_sser_r_intr intr = REG_RD_SSER(r_intr); - - if (intr.tidle == 0 && intr.urun == 0) { - printk(KERN_ERR - "sser @0x%x: spurious sser intr, flags: 0x%x\n", - regi_sser, REG_TYPE_CONV(u32, reg_sser_r_intr, intr)); - } else if (intr.urun == 0) { - hw->dma_actually_done = 1; - complete(&hw->dma_done); - } else { - /* - * Make any reception time out and notice the error, - * which it might not otherwise do data was *received* - * successfully. - */ - u32 regi_dmain = hw->dmain.regi; - - /* - * Recommended practice before acking urun is to turn - * off sser. That might not be enough to stop DMA-in - * from signalling success if the underrun was late in - * the transmission, so we disable the DMA-in - * interrupts too. - */ - REG_WRINT_SSER(rw_cfg, 0); - REG_WRINT_DI(rw_intr_mask, 0); - REG_WRINT_DI(rw_ack_intr, -1); - } - - REG_WRINT_SSER(rw_intr_mask, 0); - - /* - * We must at least ack urun together with tidle, but keep it - * simple and ack them all. - */ - REG_WRINT_SSER(rw_ack_intr, -1); - - return IRQ_HANDLED; -} - -/* - * Interrupt from receiver DMA connected to SSER, for use when the - * receiver is used, with or without the transmitter. - */ -static irqreturn_t rec_dma_interrupt(int irqno, void *arg) -{ - struct crisv32_spi_hw_info *hw = arg; - u32 regi_dmain = hw->dmain.regi; - u32 regi_sser = hw->sser.regi; - reg_dma_r_intr intr = REG_RD_DI(r_intr); - - if (intr.data == 0) { - printk(KERN_ERR - "sser @0x%x: spurious rec dma intr, flags: 0x%x\n", - regi_dmain, REG_TYPE_CONV(u32, reg_dma_r_intr, intr)); - } else { - hw->dma_actually_done = 1; - complete(&hw->dma_done); - } - - REG_WRINT_DI(rw_intr_mask, 0); - - /* Avoid false underrun indications; stop all sser interrupts. */ - REG_WRINT_SSER(rw_intr_mask, 0); - REG_WRINT_SSER(rw_ack_intr, -1); - - REG_WRINT_DI(rw_ack_intr, -1); - return IRQ_HANDLED; -} - -/* - * Set up transmitter and receiver for DMA access. We use settings - * from the "Atmel fast flash" example. - */ -static int crisv32_setup_spi_sser_for_dma_access(struct crisv32_spi_hw_info - *hw) -{ - int ret; - u32 regi_sser = hw->sser.regi; - - reg_sser_rw_cfg cfg = {0}; - reg_sser_rw_frm_cfg frm_cfg = {0}; - reg_sser_rw_tr_cfg tr_cfg = {0}; - reg_sser_rw_rec_cfg rec_cfg = {0}; - reg_sser_rw_intr_mask mask = {0}; - reg_sser_rw_extra extra = {0}; - - cfg.en = 0; - tr_cfg.tr_en = 1; - rec_cfg.rec_en = 1; - REG_WR_SSER(rw_cfg, cfg); - REG_WR_SSER(rw_tr_cfg, tr_cfg); - REG_WR_SSER(rw_rec_cfg, rec_cfg); - REG_WR_SSER(rw_intr_mask, mask); - - /* - * See 23.7.5.2 (Atmel fast flash) in the hardware documentation. - * Step 1. - */ - cfg.gate_clk = regk_sser_no; - - /* Step 2. */ - cfg.out_clk_pol = regk_sser_pos; - - /* Step 3. */ - cfg.out_clk_src = regk_sser_intern_clk; - - /* Step 4. */ - tr_cfg.sample_size = 1; - rec_cfg.sample_size = 1; - - /* Step 5. */ - frm_cfg.wordrate = 7; - - /* Step 6. */ - tr_cfg.clk_src = regk_sser_intern; - rec_cfg.clk_src = regk_sser_intern; - frm_cfg.clk_src = regk_sser_intern; - tr_cfg.clk_pol = regk_sser_neg; - frm_cfg.clk_pol = regk_sser_neg; - - /* Step 7. */ - rec_cfg.clk_pol = regk_sser_pos; - - /* Step 8. */ - frm_cfg.tr_delay = 1; - - /* Step 9. */ - frm_cfg.rec_delay = 1; - - /* Step 10. */ - tr_cfg.sh_dir = regk_sser_msbfirst; - rec_cfg.sh_dir = regk_sser_msbfirst; - - /* Step 11. */ - tr_cfg.frm_src = regk_sser_intern; - rec_cfg.frm_src = regk_sser_intern; - - /* Step 12. */ - tr_cfg.rate_ctrl = regk_sser_iso; - - /* - * Step 13. Note that 0 != tx_null, so we're good regarding - * the descriptor .md field. - */ - tr_cfg.eop_stop = 1; - - /* Step 14. */ - frm_cfg.frame_pin_use = regk_sser_gio1; - frm_cfg.frame_pin_dir = regk_sser_out; - - /* Step 15. */ - extra.clkon_en = 1; - extra.clkoff_en = 1; - - /* Step 16. We'll modify this value for each "burst". */ - extra.clkoff_cycles = 7; - - /* Step 17. */ - cfg.prepare = 1; - - /* - * Things left out from the documented startup procedure. - * It's uncertain whether all of these are needed. - */ - frm_cfg.status_pin_dir = regk_sser_in; - tr_cfg.mode = regk_sser_hispeed; - rec_cfg.mode = regk_sser_hispeed; - frm_cfg.out_on = regk_sser_intern_tb; - frm_cfg.out_off = regk_sser_rec; - frm_cfg.type = regk_sser_level; - tr_cfg.use_dma = 1; - tr_cfg.urun_stop = 1; - rec_cfg.orun_stop = 1; - rec_cfg.use_dma = 1; - rec_cfg.fifo_thr = regk_sser_inf; - frm_cfg.early_wend = regk_sser_yes; - cfg.clk_dir = regk_sser_out; - - tr_cfg.data_pin_use = regk_sser_dout; - cfg.base_freq = regk_sser_f100; - - REG_WR_SSER(rw_frm_cfg, frm_cfg); - REG_WR_SSER(rw_tr_cfg, tr_cfg); - REG_WR_SSER(rw_rec_cfg, rec_cfg); - REG_WR_SSER(rw_extra, extra); - REG_WR_SSER(rw_cfg, cfg); - hw->frm_cfg = frm_cfg; - hw->tr_cfg = tr_cfg; - hw->rec_cfg = rec_cfg; - hw->extra = extra; - hw->cfg = cfg; - - crisv32_spi_sser_set_speed_Hz(hw, hw->max_speed_Hz); - - ret = request_irq(hw->sser.irq, sser_interrupt, 0, "sser", hw); - if (ret != 0) - goto noirq; - - ret = request_irq(hw->dmain.irq, rec_dma_interrupt, 0, "sser rec", hw); - if (ret != 0) - goto free_outirq; - - crisv32_reset_dma_hw(hw->dmain.regi); - crisv32_reset_dma_hw(hw->dmaout.regi); - return 0; - - free_outirq: - free_irq(hw->sser.irq, hw); - noirq: - return ret; -} - -/* SPI-master setup function for non-DMA. */ - -static int crisv32_spi_sser_regs_master_setup(struct spi_device *spi) -{ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); - int ret = 0; - - /* Just do a little initial constraining checks. */ - if (spi->bits_per_word == 0) - spi->bits_per_word = 8; - - if (spi->bits_per_word != 8) - return -EINVAL; - - bitbang->chipselect = (spi->mode & SPI_CS_HIGH) != 0 - ? crisv32_spi_sser_chip_select_active_high - : crisv32_spi_sser_chip_select_active_low; - - if (hw->max_speed_Hz == 0) { - u32 max_speed_Hz; - - /* - * At this time; at the first call to the SPI master - * setup function, spi->max_speed_hz reflects the - * board-init value. It will be changed later on by - * the protocol master, but at the master setup call - * is the only time we actually get to see the hw max - * and thus a reasonable time to init the hw field. - */ - - /* The module parameter overrides everything. */ - if (crisv32_spi_speed_limit_Hz != 0) - max_speed_Hz = crisv32_spi_speed_limit_Hz; - /* - * I never could get hispeed mode to work for non-DMA. - * We adjust the max speed here (where we could - * presumably fix it), not in the board info file. - */ - else if (spi->max_speed_hz > 16667000) - max_speed_Hz = 16667000; - else - max_speed_Hz = spi->max_speed_hz; - - hw->max_speed_Hz = max_speed_Hz; - spi->max_speed_hz = max_speed_Hz; - - /* - * We also do one-time initialization of the hardware at this - * point. We could defer to the return to the probe-function - * from spi_bitbang_start, but other hardware setup (like - * subsequent calls to this function before that) would have - * to be deferred until then too. - */ - ret = crisv32_setup_spi_sser_for_reg_access(hw); - if (ret != 0) - return ret; - - ret = spi_bitbang_setup(spi); - if (ret != 0) - return ret; - - dev_info(&spi->dev, - "CRIS v32 SPI driver for sser%d\n", - spi->master->bus_num); - } - - return 0; -} - -/* - * SPI-master setup_transfer-function used for both DMA and non-DMA - * (single function for DMA, together with spi_bitbang_setup_transfer - * for non-DMA). - */ - -static int crisv32_spi_sser_common_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - u8 bits_per_word; - u32 hz; - int ret = 0; - - if (t) { - bits_per_word = t->bits_per_word; - hz = t->speed_hz; - } else { - bits_per_word = 0; - hz = 0; - } - - if (bits_per_word == 0) - bits_per_word = spi->bits_per_word; - - if (bits_per_word != 8) - return -EINVAL; - - if (hz == 0) - hz = spi->max_speed_hz; - - if (hz != hw->effective_speed_kHz*1000 && hz != 0) - ret = crisv32_spi_sser_set_speed_Hz(hw, hz); - - return ret; -} - -/* Helper for a SPI-master setup_transfer function for non-DMA. */ - -static int crisv32_spi_sser_regs_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - int ret = crisv32_spi_sser_common_setup_transfer(spi, t); - - if (ret != 0) - return ret; - - /* Set up the loop-over-buffer parts. */ - return spi_bitbang_setup_transfer (spi, t); -} - -/* SPI-master setup function for DMA. */ - -static int crisv32_spi_sser_dma_master_setup(struct spi_device *spi) -{ - /* - * As we don't dispatch to the spi_bitbang default function, - * we need to do whatever tests it does; keep it in sync. On - * the bright side, we can use the spi->controller_state slot; - * we use it for DMA:able memory for the descriptors and - * temporary buffers to copy non-DMA:able transfers. - */ - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); - struct crisv32_spi_dma_cs *cs; - u32 dmasize; - int ret = 0; - - if (hw->max_speed_Hz == 0) { - struct crisv32_spi_dma_descrs *descrp; - u32 descrp_dma; - u32 max_speed_Hz; - - /* The module parameter overrides everything. */ - if (crisv32_spi_speed_limit_Hz != 0) - max_speed_Hz = crisv32_spi_speed_limit_Hz; - /* - * See comment at corresponding statement in - * crisv32_spi_sser_regs_master_setup. - */ - else - max_speed_Hz = spi->max_speed_hz; - - hw->max_speed_Hz = max_speed_Hz; - spi->max_speed_hz = max_speed_Hz; - - ret = crisv32_setup_spi_sser_for_dma_access(hw); - if (ret != 0) - return ret; - - /* Allocate some extra for necessary alignment. */ - dmasize = sizeof *cs + 31 - + sizeof(struct crisv32_spi_dma_descrs); - - cs = kzalloc(dmasize, GFP_KERNEL | GFP_DMA); - if (cs == NULL) - return -ENOMEM; - - /* - * Make descriptors aligned within the allocated area, - * some-place after cs. - */ - descrp = (struct crisv32_spi_dma_descrs *) - (((u32) (cs + 1) + 31) & ~31); - descrp_dma = virt_to_phys(descrp); - - /* Set up the "constant" parts of the descriptors. */ - descrp->out_descr.eol = 1; - descrp->out_descr.intr = 1; - descrp->out_descr.out_eop = 1; - descrp->out_ctxt.saved_data = (dma_descr_data *) - (descrp_dma - + offsetof(struct crisv32_spi_dma_descrs, out_descr)); - descrp->out_ctxt.next = 0; - - descrp->in_descr.eol = 1; - descrp->in_descr.intr = 1; - descrp->in_ctxt.saved_data = (dma_descr_data *) - (descrp_dma - + offsetof(struct crisv32_spi_dma_descrs, in_descr)); - descrp->in_ctxt.next = 0; - - cs->descrp = descrp; - spi->controller_state = cs; - - init_completion(&hw->dma_done); - - dev_info(&spi->dev, - "CRIS v32 SPI driver for sser%d/DMA\n", - spi->master->bus_num); - } - - /* Do our extra constraining checks. */ - if (spi->bits_per_word == 0) - spi->bits_per_word = 8; - - if (spi->bits_per_word != 8) - return -EINVAL; - - /* SPI_LSB_FIRST deliberately left out, and we only support mode 3. */ - if ((spi->mode & ~(SPI_TX_1|SPI_CS_HIGH)) != SPI_MODE_3) - return -EINVAL; - - bitbang->chipselect = (spi->mode & SPI_CS_HIGH) != 0 - ? crisv32_spi_sser_chip_select_active_high - : crisv32_spi_sser_chip_select_active_low; - - ret = bitbang->setup_transfer(spi, NULL); - if (ret != 0) - return ret; - - /* Remember to de-assert chip-select before the first transfer. */ - spin_lock(&bitbang->lock); - if (!bitbang->busy) { - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(hw->half_cycle_delay_ns); - } - spin_unlock(&bitbang->lock); - - return 0; -} - -/* SPI-master cleanup function for DMA. */ - -static void crisv32_spi_sser_dma_cleanup(struct spi_device *spi) -{ - kfree(spi->controller_state); - spi->controller_state = NULL; -} - -/* - * Set up DMA transmitter descriptors for a chunk of data. - * The caller is responsible for working around TR 106. - */ -static void crisv32_spi_sser_setup_dma_descr_out(u32 regi, - struct crisv32_spi_dma_cs *cs, - u32 out_phys, u32 chunk_len) -{ - BUG_ON(chunk_len > DMA_CHUNKSIZ); - struct crisv32_spi_dma_descrs *descrp = cs->descrp; - u32 descrp_dma = virt_to_phys(descrp); - - descrp->out_descr.buf = (u8 *) out_phys; - descrp->out_descr.after = (u8 *) out_phys + chunk_len; - descrp->out_ctxt.saved_data_buf = (u8 *) out_phys; - - DMA_START_CONTEXT(regi, - descrp_dma - + offsetof(struct crisv32_spi_dma_descrs, out_ctxt)); -} - -/* - * Set up DMA receiver descriptors for a chunk of data. - * Also, work around TR 106. - */ -static void crisv32_spi_sser_setup_dma_descr_in(u32 regi_dmain, - struct crisv32_spi_dma_cs *cs, - u32 in_phys, u32 chunk_len) -{ - BUG_ON(chunk_len > DMA_CHUNKSIZ); - struct crisv32_spi_dma_descrs *descrp = cs->descrp; - u32 descrp_dma = virt_to_phys(descrp); - - descrp->in_descr.buf = (u8 *) in_phys; - descrp->in_descr.after = (u8 *) in_phys + chunk_len; - descrp->in_ctxt.saved_data_buf = (u8 *) in_phys; - - flush_dma_descr(&descrp->in_descr, 1); - - DMA_START_CONTEXT(regi_dmain, - descrp_dma - + offsetof(struct crisv32_spi_dma_descrs, in_ctxt)); -} - -/* - * SPI-bitbang txrx_bufs function for DMA. - * FIXME: We have SG DMA descriptors; use them. - * (Requires abandoning the spi_bitbang framework if done reasonably.) - */ -static int crisv32_spi_sser_dma_txrx_bufs(struct spi_device *spi, - struct spi_transfer *t) -{ - struct crisv32_spi_dma_cs *cs = spi->controller_state; - struct crisv32_spi_hw_info *hw = spidev_to_hw(spi); - u32 len = t->len; - reg_sser_rw_cfg cfg = hw->cfg; - reg_sser_rw_tr_cfg tr_cfg = hw->tr_cfg; - reg_sser_rw_rec_cfg rec_cfg = hw->rec_cfg; - reg_sser_rw_extra extra = hw->extra; - u32 regi_sser = hw->sser.regi; - u32 dmain = 0; - u32 dmaout = 0; - u32 regi_dmain = hw->dmain.regi; - u8 *rx_buf = t->rx_buf; - - /* - * Using IRQ+completion is measured to give an overhead of 14 - * us, so let's instead busy-wait for the time that would be - * wasted anyway, and get back sooner. We're not counting in - * other overhead such as the DMA descriptor in the - * time-expression, which causes us to use busy-wait for - * data-lengths that actually take a bit longer than - * IRQ_USAGE_THRESHOLD_NS. Still, with IRQ_USAGE_THRESHOLD_NS - * = 14000, the threshold is for 20 MHz => 35 bytes, 25 => 44 - * and 50 => 88 and the typical SPI transfer lengths for - * SDcard are { 1, 2, 7, 512 } bytes so a more complicated - * would likely give nothing but worse performance due to - * complexity. - */ - int use_irq = len * hw->half_cycle_delay_ns - > IRQ_USAGE_THRESHOLD_NS / 8 / 2; - - if (len > DMA_CHUNKSIZ) { - /* - * It should be quite easy to adjust the code if the need - * arises for something much larger than the preallocated - * buffers (which could themselves easily just be increased) - * but still what fits in extra.clkoff_cycles: kmalloc a - * temporary dmaable buffer in this function and free it at - * the end. No need to optimize rare requests. Until then, - * we'll keep the code as simple as performance allows. - * Alternatively or if we need to send even larger data, - * consider calling self with the required number of "faked" - * shorter transfers here. - */ - dev_err(&spi->dev, - "Trying to transfer %d > max %d bytes:" - " need to adjust the SPI driver\n", - len, DMA_CHUNKSIZ); - return -EMSGSIZE; - } - - /* - * Need to separately tell the hispeed machinery the number of - * bits in this transmission. - */ - extra.clkoff_cycles = len * 8 - 1; - - if (t->tx_buf != NULL) { - if (t->tx_dma == 0) { - memcpy(cs->tx_buf, t->tx_buf, len); - dmaout = virt_to_phys(cs->tx_buf); - } else - dmaout = t->tx_dma; - - crisv32_spi_sser_setup_dma_descr_out(hw->dmaout.regi, - cs, dmaout, - len); - - /* No need to do anything for TR 106; this DMA only reads. */ - tr_cfg.tr_en = 1; - tr_cfg.data_pin_use = regk_sser_dout; - } else { - tr_cfg.data_pin_use = (spi->mode & SPI_TX_1) - ? regk_sser_gio1 : regk_sser_gio0; - tr_cfg.tr_en = 0; - } - - if (rx_buf != 0) { - if (t->rx_dma == 0) - dmain = virt_to_phys(cs->rx_buf); - else - dmain = t->rx_dma; - - crisv32_spi_sser_setup_dma_descr_in(regi_dmain, cs, - dmain, len); - rec_cfg.rec_en = 1; - - REG_WRINT_SSER(rw_ack_intr, -1); - REG_WRINT_DI(rw_ack_intr, -1); - - /* - * If we're receiving, use the rec data interrupt from DMA as - * a signal that the HW is done. - */ - if (use_irq) { - reg_sser_rw_intr_mask mask = { .urun = 1 }; - reg_dma_rw_intr_mask dmask = { .data = 1 }; - - REG_WR_DI(rw_intr_mask, dmask); - - /* - * Catch transmitter underruns too. We don't - * have to conditionalize that on the - * transmitter being enabled; it's off when - * the transmitter is off. Any overruns will - * be indicated by a timeout, so we don't have - * to check for that specifically. - */ - REG_WR_SSER(rw_intr_mask, mask); - } - } else { - rec_cfg.rec_en = 0; - - /* - * Ack previous overrun, underrun and tidle interrupts. Or - * why not all. We'll get orun and urun "normally" due to the - * way hispeed is (documented to) work and need to clear them, - * and we'll have a tidle from a previous transmit if we used - * to both receive and transmit, but now only transmit. - */ - REG_WRINT_SSER(rw_ack_intr, -1); - - if (use_irq) { - reg_sser_rw_intr_mask mask = { .urun = 1, .tidle = 1 }; - REG_WR_SSER(rw_intr_mask, mask); - } - } - - REG_WR_SSER(rw_rec_cfg, rec_cfg); - REG_WR_SSER(rw_tr_cfg, tr_cfg); - REG_WR_SSER(rw_extra, extra); - - /* - * Barriers are needed to make sure that the completion inits don't - * migrate past the register writes due to gcc scheduling. - */ - mb(); - hw->dma_actually_done = 0; - INIT_COMPLETION(hw->dma_done); - mb(); - - /* - * Wait until DMA tx FIFO has more than one byte (it reads one - * directly then one "very quickly") before starting sser tx. - */ - if (tr_cfg.tr_en) { - u32 regi_dmaout = hw->dmaout.regi; - u32 minlen = len > 2 ? 2 : len; - while ((REG_RD_DO(rw_stat)).buf < minlen) - ; - } - - /* Wait until DMA-in is finished reading the descriptors. */ - if (rec_cfg.rec_en) - while (DMA_BUSY(regi_dmain)) - ; - /* - * Wait 3 cycles before enabling (with .prepare = 1). - * FIXME: Can we cut this by some time already passed? - */ - ndelay(3 * 2 * hw->half_cycle_delay_ns); - cfg.en = 1; - REG_WR_SSER(rw_cfg, cfg); - - /* - * Wait 3 more cycles plus 30 ns before letting go. - * FIXME: Can we do something else before but after the - * previous cfg write and cut this by the time already passed? - */ - cfg.prepare = 0; - hw->cfg = cfg; - ndelay(3 * 2 * hw->half_cycle_delay_ns + 30); - - REG_WR_SSER(rw_cfg, cfg); - - /*, We'll disable sser next the time we change the configuration. */ - cfg.en = 0; - cfg.prepare = 1; - hw->cfg = cfg; - - if (!use_irq) { - /* - * We use a timeout corresponding to one iteration per ns, - * which of course is at least five * insns / loop times as - * much as reality, but we'll avoid a need for reading hw - * timers directly. - */ - u32 countdown = IRQ_USAGE_THRESHOLD_NS; - - do - if (rec_cfg.rec_en == 0) { - /* Using the transmitter only. */ - reg_sser_r_intr intr = REG_RD_SSER(r_intr); - - if (intr.tidle != 0) { - /* - * Almost done... Just check if we - * had a transmitter underrun too. - */ - if (!intr.urun) - goto transmission_done; - - /* - * Fall over to the "time is up" case; - * no need to provide a special path - * for the error case. - */ - countdown = 1; - } - } else { - /* Using at least the receiver. */ - if ((REG_RD_DI(r_intr)).data != 0) { - if ((REG_RD_SSER(r_intr)).urun == 0) - goto transmission_done; - countdown = 1; - } - } - while (--countdown != 0); - - /* - * The time is up. Something might be wrong, or perhaps we've - * started using data lengths where the threshold was about a - * magnitude wrong. Fall over to IRQ. Remember not to ack - * interrupts here (but always above, before starting), else - * we'll have a race condition with the interrupt. - */ - if (!rec_cfg.rec_en) { - reg_sser_rw_intr_mask mask = { .urun = 1, .tidle = 1 }; - REG_WR_SSER(rw_intr_mask, mask); - } else { - reg_dma_rw_intr_mask dmask = { .data = 1 }; - reg_sser_rw_intr_mask mask = { .urun = 1 }; - - /* - * Never mind checking for tr being disabled; urun - * won't happen then. - */ - REG_WR_SSER(rw_intr_mask, mask); - REG_WR_DI(rw_intr_mask, dmask); - } - } - - if (!wait_for_completion_timeout(&hw->dma_done, hw->dma_timeout) - /* - * Have to keep track manually too, else we'll get a timeout - * indication for being scheduled out too long, while the - * completion will still have trigged. - */ - && !hw->dma_actually_done) { - u32 regi_dmaout = hw->dmaout.regi; - - /* - * Transfer timed out. Should not happen for a - * working controller, except perhaps if the system is - * badly conditioned, causing DMA memory bandwidth - * starvation. Not much to do afterwards, but perhaps - * reset DMA and sser and hope it works the next time. - */ - REG_WRINT_SSER(rw_cfg, 0); - REG_WR_SSER(rw_cfg, cfg); - REG_WRINT_SSER(rw_intr_mask, 0); - REG_WRINT_DI(rw_intr_mask, 0); - REG_WRINT_SSER(rw_ack_intr, -1); - crisv32_reset_dma_hw(hw->dmain.regi); - crisv32_reset_dma_hw(hw->dmaout.regi); - - dev_err(&spi->dev, "timeout %u bytes %u kHz\n", - len, hw->effective_speed_kHz); - dev_err(&spi->dev, "sser=(%x,%x,%x,%x,%x)\n", - REG_RDINT_SSER(rw_cfg), REG_RDINT_SSER(rw_tr_cfg), - REG_RDINT_SSER(rw_rec_cfg), REG_RDINT_SSER(rw_extra), - REG_RDINT_SSER(r_intr)); - dev_err(&spi->dev, "tx=(%x,%x,%x,%x)\n", - dmaout, REG_RDINT_DO(rw_stat), REG_RDINT_DO(rw_data), - REG_RDINT_DO(r_intr)); - dev_err(&spi->dev, "rx=(%x,%x,%x,%x)\n", - dmain, REG_RDINT_DI(rw_stat), REG_RDINT_DI(rw_data), - REG_RDINT_DI(r_intr)); - return -EIO; - } - - transmission_done: - /* Wait for the last half-cycle of the last cycle. */ - crisv32_spi_sser_wait_halfabit(hw); - - /* Reset for another call. */ - REG_WR_SSER(rw_cfg, cfg); - - /* - * If we had to use the temp DMAable rec buffer, copy it to the right - * position. - */ - if (t->rx_buf != 0 && t->rx_dma == 0) - memcpy (t->rx_buf, cs->rx_buf, len); - - /* - * All clear. The interrupt function disabled the interrupt, we don't - * have to do more. - */ - return len; -} - -/* Platform-device probe function. */ - -static int __devinit crisv32_spi_sser_probe(struct platform_device *dev) -{ - struct spi_master *master; - struct crisv32_spi_sser_devdata *dd; - struct crisv32_spi_hw_info *hw; - struct resource *res; - struct crisv32_spi_sser_controller_data *gc; - int ret; - - /* - * We need to get the controller data as a hardware resource, - * or else it wouldn't be available until *after* the - * spi_bitbang_start call! - */ - res = platform_get_resource_byname(dev, 0, "controller_data_ptr"); - if (res == NULL) { - dev_err(&dev->dev, - "can't get controller_data resource at probe\n"); - return -EIO; - } - - gc = (struct crisv32_spi_sser_controller_data *) res->start; - - master = spi_alloc_master(&dev->dev, sizeof *dd); - if (master == NULL) { - dev_err(&dev->dev, "failed to allocate spi master\n"); - ret = -ENOMEM; - goto err; - } - - dd = spi_master_get_devdata(master); - platform_set_drvdata(dev, dd); - - /* - * The device data asks for this driver, and holds the id - * number, which must be unique among the same-type devices. - * We use this as the number of this SPI bus. - */ - master->bus_num = dev->id; - - /* Setup SPI bitbang adapter hooks. */ - dd->bitbang.master = spi_master_get(master); - dd->bitbang.chipselect = crisv32_spi_sser_chip_select_active_low; - - hw = &dd->hw; - hw->gc = gc; - - /* Pre-spi_bitbang_start setup. */ - if (gc->using_dma) { - /* Setup DMA and interrupts. */ - ret = gc->iface_allocate(&hw->sser, &hw->dmain, &hw->dmaout); - if (ret != 0) - goto err_no_regs; - - dd->bitbang.master->setup = crisv32_spi_sser_dma_master_setup; - dd->bitbang.setup_transfer - = crisv32_spi_sser_common_setup_transfer; - dd->bitbang.txrx_bufs = crisv32_spi_sser_dma_txrx_bufs; - dd->bitbang.master->cleanup = crisv32_spi_sser_dma_cleanup; - } else { - /* Just registers, then. */ - ret = gc->iface_allocate(&hw->sser, NULL, NULL); - if (ret != 0) - goto err_no_regs; - - dd->bitbang.master->setup - = crisv32_spi_sser_regs_master_setup; - dd->bitbang.setup_transfer - = crisv32_spi_sser_regs_setup_transfer; - dd->bitbang.master->cleanup = spi_bitbang_cleanup; - - /* - * We can do all modes pretty simply, but I have no - * simple enough way to test them, so I won't. - */ - dd->bitbang.txrx_word[SPI_MODE_3] - = crisv32_spi_sser_txrx_mode3; - } - - ret = spi_bitbang_start(&dd->bitbang); - if (ret) - goto err_no_bitbang; - - /* - * We don't have a dev_info here, as initialization that may fail is - * postponed to the first master->setup call. It's called from - * spi_bitbang_start (above), where the call-chain doesn't look too - * close at error return values; we'll get here successfully anyway, - * so emitting a separate message here is at most confusing. - */ - dev_dbg(&dev->dev, - "CRIS v32 SPI driver for sser%d%s present\n", - master->bus_num, - gc->using_dma ? "/DMA" : ""); - - return 0; - - err_no_bitbang: - gc->iface_free(); - - err_no_regs: - platform_set_drvdata(dev, NULL); - spi_master_put(dd->bitbang.master); - - err: - return ret; -} - -/* Platform-device remove-function. */ - -static int __devexit crisv32_spi_sser_remove(struct platform_device *dev) -{ - struct crisv32_spi_sser_devdata *dd = platform_get_drvdata(dev); - struct crisv32_spi_hw_info *hw = &dd->hw; - struct crisv32_spi_sser_controller_data *gc = hw->gc; - int ret; - - /* We need to stop all bitbanging activity separately. */ - ret = spi_bitbang_stop(&dd->bitbang); - if (ret != 0) - return ret; - - spi_master_put(dd->bitbang.master); - - /* - * If we get here, the queue is empty and there's no activity; - * it's safe to flip the switch on the interfaces. - */ - if (gc->using_dma) { - u32 regi_dmain = hw->dmain.regi; - u32 regi_dmaout = hw->dmaout.regi; - u32 regi_sser = hw->sser.regi; - - REG_WRINT_SSER(rw_intr_mask, 0); - REG_WRINT_DI(rw_intr_mask, 0); - REG_WRINT_DO(rw_intr_mask, 0); - hw->cfg.en = 0; - REG_WR_SSER(rw_cfg, hw->cfg); - DMA_RESET(regi_dmain); - DMA_RESET(regi_dmaout); - free_irq(hw->sser.irq, hw); - free_irq(hw->dmain.irq, hw); - } - - gc->iface_free(); - - platform_set_drvdata(dev, NULL); - return 0; -} - -/* - * For the time being, there's no suspend/resume support to care - * about, so those handlers default to NULL. - */ -static struct platform_driver crisv32_spi_sser_drv = { - .probe = crisv32_spi_sser_probe, - .remove = __devexit_p(crisv32_spi_sser_remove), - .driver = { - .name = "spi_crisv32_sser", - .owner = THIS_MODULE, - }, -}; - -/* Module init function. */ - -static int __devinit crisv32_spi_sser_init(void) -{ - return platform_driver_register(&crisv32_spi_sser_drv); -} - -/* Module exit function. */ - -static void __devexit crisv32_spi_sser_exit(void) -{ - platform_driver_unregister(&crisv32_spi_sser_drv); -} - -/* Setter function for speed limit. */ - -static int crisv32_spi_speed_limit_Hz_setter(const char *val, - struct kernel_param *kp) -{ - char *endp; - ulong num = simple_strtoul(val, &endp, 0); - if (endp == val - || *endp != 0 - || num <= 0 - /* - * We can't go above 100 MHz speed. Actually we can't go - * above 50 MHz using the sser support but it might make - * sense trying. - */ - || num > 100000000) - return -EINVAL; - *(ulong *) kp->arg = num; - return 0; -} - -module_param_call(crisv32_spi_max_speed_hz, - crisv32_spi_speed_limit_Hz_setter, param_get_ulong, - &crisv32_spi_speed_limit_Hz, 0644); - -module_init(crisv32_spi_sser_init); -module_exit(crisv32_spi_sser_exit); - -MODULE_DESCRIPTION("CRIS v32 SPI-SSER Driver"); -MODULE_AUTHOR("Hans-Peter Nilsson, "); -MODULE_LICENSE("GPL"); diff --git a/target/linux/etrax/files/drivers/usb/host/hc-cris-dbg.h b/target/linux/etrax/files/drivers/usb/host/hc-cris-dbg.h deleted file mode 100644 index f53f5581b1..0000000000 --- a/target/linux/etrax/files/drivers/usb/host/hc-cris-dbg.h +++ /dev/null @@ -1,141 +0,0 @@ - -/* macros for debug output */ - -#define hcd_dbg(hcd, fmt, args...) \ - dev_info(hcd->self.controller, fmt, ## args) -#define hcd_err(hcd, fmt, args...) \ - dev_err(hcd->self.controller, fmt, ## args) -#define hcd_info(hcd, fmt, args...) \ - dev_info(hcd->self.controller, fmt, ## args) -#define hcd_warn(hcd, fmt, args...) \ - dev_warn(hcd->self.controller, fmt, ## args) - -/* -#define devdrv_dbg(fmt, args...) \ - printk(KERN_INFO "usb_devdrv dbg: ");printk(fmt, ## args) -*/ -#define devdrv_dbg(fmt, args...) {} - -#define devdrv_err(fmt, args...) \ - printk(KERN_ERR "usb_devdrv error: ");printk(fmt, ## args) -#define devdrv_info(fmt, args...) \ - printk(KERN_INFO "usb_devdrv: ");printk(fmt, ## args) - -#define irq_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_irq dbg: ");printk(fmt, ## args) -#define irq_err(fmt, args...) \ - printk(KERN_ERR "crisv10_irq error: ");printk(fmt, ## args) -#define irq_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_irq warn: ");printk(fmt, ## args) -#define irq_info(fmt, args...) \ - printk(KERN_INFO "crisv10_hcd: ");printk(fmt, ## args) - -/* -#define rh_dbg(fmt, args...) \ - printk(KERN_DEBUG "crisv10_rh dbg: ");printk(fmt, ## args) -*/ -#define rh_dbg(fmt, args...) {} - -#define rh_err(fmt, args...) \ - printk(KERN_ERR "crisv10_rh error: ");printk(fmt, ## args) -#define rh_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_rh warning: ");printk(fmt, ## args) -#define rh_info(fmt, args...) \ - printk(KERN_INFO "crisv10_rh: ");printk(fmt, ## args) - -/* -#define tc_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_tc dbg: ");printk(fmt, ## args) -*/ -#define tc_dbg(fmt, args...) {while(0){}} - -#define tc_err(fmt, args...) \ - printk(KERN_ERR "crisv10_tc error: ");printk(fmt, ## args) -/* -#define tc_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_tc warning: ");printk(fmt, ## args) -*/ -#define tc_warn(fmt, args...) {while(0){}} - -#define tc_info(fmt, args...) \ - printk(KERN_INFO "crisv10_tc: ");printk(fmt, ## args) - - -/* Debug print-outs for various traffic types */ - -#define intr_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_intr warning: ");printk(fmt, ## args) -/* -#define intr_dbg(fmt, args...) \ - printk(KERN_DEBUG "crisv10_intr dbg: ");printk(fmt, ## args) -*/ -#define intr_dbg(fmt, args...) {while(0){}} - - -#define isoc_err(fmt, args...) \ - printk(KERN_ERR "crisv10_isoc error: ");printk(fmt, ## args) -/* -#define isoc_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_isoc warning: ");printk(fmt, ## args) -*/ -#define isoc_warn(fmt, args...) {while(0){}} - -/* -#define isoc_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_isoc dbg: ");printk(fmt, ## args) -*/ -#define isoc_dbg(fmt, args...) {while(0){}} - -/* -#define timer_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_timer warning: ");printk(fmt, ## args) -*/ -#define timer_warn(fmt, args...) {while(0){}} - -/* -#define timer_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_timer dbg: ");printk(fmt, ## args) -*/ -#define timer_dbg(fmt, args...) {while(0){}} - - -/* Debug printouts for events related to late finishing of URBs */ -/* -#define late_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_late dbg: ");printk(fmt, ## args) -*/ -#define late_dbg(fmt, args...) {while(0){}} - -#define late_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_late warning: ");printk(fmt, ## args) -/* -#define errno_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_errno dbg: ");printk(fmt, ## args) -*/ -#define errno_dbg(fmt, args...) {while(0){}} - - -#define dma_dbg(fmt, args...) \ - printk(KERN_INFO "crisv10_dma dbg: ");printk(fmt, ## args) -#define dma_err(fmt, args...) \ - printk(KERN_ERR "crisv10_dma error: ");printk(fmt, ## args) -#define dma_warn(fmt, args...) \ - printk(KERN_INFO "crisv10_dma warning: ");printk(fmt, ## args) -#define dma_info(fmt, args...) \ - printk(KERN_INFO "crisv10_dma: ");printk(fmt, ## args) - - - -#define str_dir(pipe) \ - (usb_pipeout(pipe) ? "out" : "in") -#define str_type(pipe) \ - ({ \ - char *s = "?"; \ - switch (usb_pipetype(pipe)) { \ - case PIPE_ISOCHRONOUS: s = "iso"; break; \ - case PIPE_INTERRUPT: s = "intr"; break; \ - case PIPE_CONTROL: s = "ctrl"; break; \ - case PIPE_BULK: s = "bulk"; break; \ - }; \ - s; \ - }) diff --git a/target/linux/etrax/files/include/linux/mtd/mtdram.h b/target/linux/etrax/files/include/linux/mtd/mtdram.h deleted file mode 100644 index 400cb240c8..0000000000 --- a/target/linux/etrax/files/include/linux/mtd/mtdram.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __MTD_MTDRAM_H__ -#define __MTD_MTDRAM_H__ - -#ifdef __KERNEL__ -#include -int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name); - -#endif /* __KERNEL__ */ -#endif /* __MTD_MTDRAM_H__ */ diff --git a/target/linux/etrax/image/Makefile b/target/linux/etrax/image/Makefile index 592cea5136..9f716202c3 100644 --- a/target/linux/etrax/image/Makefile +++ b/target/linux/etrax/image/Makefile @@ -8,44 +8,32 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/image.mk -FOXBOARD:=custom MCM 416 816 832 -FOXBOARD_4MB:=MCM 416 -FOXBOARD_8MB:=custom 816 832 - define Image/BuildKernel - for f in $(FOXBOARD); do \ - cp $(KDIR)/vmlinuz_$$$$f $(BIN_DIR)/openwrt-$(BOARD)-zImage_$$$$f; \ - done + cp $(KDIR)/vmlinuz $(BIN_DIR)/openwrt-$(BOARD)-zImage endef define Image/Prepare - for f in $(FOXBOARD); do \ - cp $(LINUX_DIR)/arch/cris/boot/zImage_$$$$f $(KDIR)/vmlinuz_$$$$f; \ - done + cp $(LINUX_DIR)/arch/cris/boot/zImage $(KDIR)/vmlinuz $(MAKE) -C e100boot compile $(MAKE) -C mkfimage compile $(INSTALL_BIN) ./boot_linux $(BIN_DIR) endef define Image/Build/generic - for f in $(2); do \ - mkfimage $(KDIR)/vmlinuz_$$$$f $(KDIR)/vmlinuz_$$$$f.tmp ; \ - cat $(KDIR)/vmlinuz_$$$$f.tmp $(KDIR)/root.$(1) > $(KDIR)/fimage.$(1)_$$$$f.tmp; \ - dd if=$(KDIR)/fimage.$(1)_$$$$f.tmp of=$(KDIR)/fimage.$(1)_$$$$f bs=$(3) conv=sync; \ - cp $(KDIR)/fimage.$(1)_$$$$f $(BIN_DIR)/openwrt-$(BOARD)-$(1)-fimage_$$$$f; \ - done + mkfimage $(KDIR)/vmlinuz $(KDIR)/vmlinuz.tmp + cat $(KDIR)/vmlinuz.tmp $(KDIR)/root.$(1) > $(KDIR)/fimage.$(1).tmp + dd if=$(KDIR)/fimage.$(1).tmp of=$(KDIR)/fimage.$(1) bs=$(2) conv=sync + cp $(KDIR)/fimage.$(1) $(BIN_DIR)/openwrt-$(BOARD)-$(1)-fimage endef define Image/Build/jffs2-64k $(call prepare_generic_jffs-64k,$(KDIR)/root.jff2-64k) - $(call Image/Build/generic,$(1),$(FOXBOARD_4MB),4194304) - $(call Image/Build/generic,$(1),$(FOXBOARD_8MB),8388608) + $(call Image/Build/generic,$(1),4194304) endef define Image/Build/squashfs $(call prepare_generic_squashfs,$(KDIR)/root.squashfs) - $(call Image/Build/generic,$(1),$(FOXBOARD_4MB),4194304) - $(call Image/Build/generic,$(1),$(FOXBOARD_8MB),8388608) + $(call Image/Build/generic,$(1),4194304) endef define Image/Build diff --git a/target/linux/etrax/image/mkfimage/Makefile b/target/linux/etrax/image/mkfimage/Makefile index e907e73aca..f97d098d9b 100644 --- a/target/linux/etrax/image/mkfimage/Makefile +++ b/target/linux/etrax/image/mkfimage/Makefile @@ -24,7 +24,7 @@ define Build/Compile endef define Build/InstallDev - $(INSTALL_BIN) $(PKG_BUILD_DIR)/mkfimage $(STAGING_DIR)/bin/mkfimage + $(INSTALL_BIN) $(PKG_BUILD_DIR)/mkfimage $(STAGING_DIR_HOST)/bin/mkfimage endef $(eval $(call Build/DefaultTargets)) diff --git a/target/linux/etrax/image/mkfimage/src/mkfimage.c b/target/linux/etrax/image/mkfimage/src/mkfimage.c index 51b8192de9..6904170cfe 100644 --- a/target/linux/etrax/image/mkfimage/src/mkfimage.c +++ b/target/linux/etrax/image/mkfimage/src/mkfimage.c @@ -17,49 +17,49 @@ int main(int argc, char **argv){ printf("%s in out\n", argv[0]); return 1; } - + printf("Generating image\n"); - + FILE *vmlinux = fopen(argv[1], "r"); FILE *vmlinux_out = fopen(argv[2], "w"); if((!vmlinux) || (!vmlinux_out)){ printf("Error opening a file\n"); return 1; } - + stat(argv[1], &s); size_vmlinux = s.st_size; real_size_vmlinux = (size_vmlinux & 0xffff0000) + 0x10000; printf("vmlinux = 0x%.08X / 0x%.08X\n", size_vmlinux, real_size_vmlinux); - + unsigned int t = fread(buffer, 1, 64 * 1024, vmlinux); for(loop = 0; loop < (64 * 1024) - sizeof(magic_str); loop++){ if(buffer[loop] == magic_str[0]){ if((magic = strstr(&buffer[loop], magic_str))){ - printf("Magic at 0x%.08X %p %p\n", magic - buffer, magic, buffer); + printf("Magic at 0x%.08X %p %p\n", magic - buffer, magic, buffer); printf("Found Magic %X%X%X%X\n", buffer[loop + strlen(magic_str)], buffer[loop + strlen(magic_str) + 2], buffer[loop + strlen(magic_str) + 1], buffer[loop + strlen(magic_str) + 3]); - + buffer[loop + strlen(magic_str)] = real_size_vmlinux >> 24; buffer[loop + strlen(magic_str) + 2] = (real_size_vmlinux >> 16) & 0xff; buffer[loop + strlen(magic_str) + 1] = (real_size_vmlinux >> 8) & 0xff; buffer[loop + strlen(magic_str) + 3] = (real_size_vmlinux) & 0xff; - + printf("Replaced with %.02X%.02X%.02X%.02X\n", buffer[loop + strlen(magic_str)], buffer[loop + strlen(magic_str) + 2], buffer[loop + strlen(magic_str) + 1], buffer[loop + strlen(magic_str) + 3]); - + } } } - - fwrite(buffer, 1, 64 * 1024, vmlinux_out); + + fwrite(buffer, 1, 64 * 1024, vmlinux_out); real_size_vmlinux -= 64 * 1024; do { real_size_vmlinux -= 64 * 1024; diff --git a/target/linux/etrax/patches/100-compile_fixes.patch b/target/linux/etrax/patches/100-compile_fixes.patch new file mode 100644 index 0000000000..93e434c99d --- /dev/null +++ b/target/linux/etrax/patches/100-compile_fixes.patch @@ -0,0 +1,139 @@ +Index: linux-2.6.25/arch/cris/mm/init.c +=================================================================== +--- linux-2.6.25.orig/arch/cris/mm/init.c 2008-05-03 09:53:53.000000000 +0100 ++++ linux-2.6.25/arch/cris/mm/init.c 2008-05-03 09:54:05.000000000 +0100 +@@ -112,3 +112,7 @@ + printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n", + (unsigned long)((&__init_end - &__init_begin) >> 10)); + } ++ ++void free_initrd_mem(unsigned long start, unsigned long end) ++{ ++} +Index: linux-2.6.25/arch/cris/boot/compressed/Makefile +=================================================================== +--- linux-2.6.25.orig/arch/cris/boot/compressed/Makefile 2008-05-03 10:00:53.000000000 +0100 ++++ linux-2.6.25/arch/cris/boot/compressed/Makefile 2008-05-03 10:01:12.000000000 +0100 +@@ -7,7 +7,7 @@ + LD = ld-cris + ldflags-y += -T $(obj)/decompress.ld + OBJECTS = $(obj)/head.o $(obj)/misc.o +-OBJCOPY = objcopy-cris ++OBJCOPY = /usr/local/cris/objcopy-cris + OBJCOPYFLAGS = -O binary --remove-section=.bss + + quiet_cmd_image = BUILD $@ +Index: linux-2.6.25/arch/cris/boot/Makefile +=================================================================== +--- linux-2.6.25.orig/arch/cris/boot/Makefile 2008-04-17 03:49:44.000000000 +0100 ++++ linux-2.6.25/arch/cris/boot/Makefile 2008-05-03 10:05:56.000000000 +0100 +@@ -2,10 +2,10 @@ + # arch/cris/arch-v10/boot/Makefile + # + +-OBJCOPY = objcopy-cris ++OBJCOPY = /usr/local/cris/objcopy-cris + OBJCOPYFLAGS = -O binary --remove-section=.bss + +-subdir- := compressed rescue ++subdir- := compressed + targets := Image + + $(obj)/Image: vmlinux FORCE +@@ -14,7 +14,6 @@ + + $(obj)/compressed/vmlinux: $(obj)/Image FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ +- $(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin + + $(obj)/zImage: $(obj)/compressed/vmlinux + @cp $< $@ +Index: linux-2.6.25/arch/cris/boot/compressed/Makefile +=================================================================== +--- linux-2.6.25.orig/arch/cris/boot/compressed/Makefile 2008-05-03 10:01:12.000000000 +0100 ++++ linux-2.6.25/arch/cris/boot/compressed/Makefile 2008-05-03 16:29:55.000000000 +0100 +@@ -2,9 +2,8 @@ + # arch/cris/arch-v10/boot/compressed/Makefile + # + +-CC = gcc-cris -melf $(LINUXINCLUDE) + ccflags-y += -O2 +-LD = ld-cris ++LD=/usr/local/cris/ld-cris + ldflags-y += -T $(obj)/decompress.ld + OBJECTS = $(obj)/head.o $(obj)/misc.o + OBJCOPY = /usr/local/cris/objcopy-cris +@@ -22,10 +21,10 @@ + $(call if_changed,objcopy) + + $(obj)/head.o: $(obj)/head.S .config +- @$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@ ++ /usr/local/cris/gcc-cris -melf $(LINUXINCLUDE) -D__ASSEMBLY__ -traditional -c $< -o $@ + + $(obj)/misc.o: $(obj)/misc.c .config +- @$(CC) -D__KERNEL__ -c $< -o $@ ++ /usr/local/cris/gcc-cris -melf $(LINUXINCLUDE) -D__KERNEL__ -c $< -o $@ + + $(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE + $(call if_changed,image) +Index: linux-2.6.25/arch/cris/boot/compressed/misc.c +=================================================================== +--- linux-2.6.25.orig/arch/cris/boot/compressed/misc.c 2008-05-03 16:22:44.000000000 +0100 ++++ linux-2.6.25/arch/cris/boot/compressed/misc.c 2008-05-03 16:23:26.000000000 +0100 +@@ -5,7 +5,7 @@ + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 +- * puts by Nick Holloway 1993, better puts by Martin Mares 1995 ++ * putstr by Nick Holloway 1993, better putstr by Martin Mares 1995 + * adaptation for Linux/CRIS Axis Communications AB, 1999 + * + */ +@@ -99,7 +99,7 @@ + static void gzip_mark(void **); + static void gzip_release(void **); + +-static void puts(const char *); ++static void putstr(const char *); + + /* the "heap" is put directly after the BSS ends, at end */ + +@@ -139,7 +139,7 @@ + /* decompressor info and error messages to serial console */ + + static void +-puts(const char *s) ++putstr(const char *s) + { + #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL + while(*s) { +@@ -209,9 +209,9 @@ + static void + error(char *x) + { +- puts("\n\n"); +- puts(x); +- puts("\n\n -- System halted\n"); ++ putstr("\n\n"); ++ putstr(x); ++ putstr("\n\n -- System halted\n"); + + while(1); /* Halt */ + } +@@ -257,14 +257,7 @@ + + makecrc(); + +- __asm__ volatile ("move vr,%0" : "=rm" (revision)); +- if (revision < 10) +- { +- puts("You need an ETRAX 100LX to run linux 2.6\n"); +- while(1); +- } +- +- puts("Uncompressing Linux...\n"); ++ putstr("Uncompressing Linux...\n"); + gunzip(); +- puts("Done. Now booting the kernel.\n"); ++ putstr("Done. Now booting the kernel.\n"); + }