diff options
author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-12-11 09:00:06 +0000 |
---|---|---|
committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-12-11 09:00:06 +0000 |
commit | a7f49cd3e861f1c192081a543a711fde8d7c1f08 (patch) | |
tree | 51fa815473f502715554aa9220d1b822d777dd93 /target/linux/adm5120/files | |
parent | c0d490d3c5d11147130b51b65bb1188a0b60878a (diff) |
[adm5120] new experimental driver for the CF slot on the RouterBOARD 153
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@9707 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/adm5120/files')
3 files changed, 323 insertions, 19 deletions
diff --git a/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c b/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c index 1ca151412..102fa5615 100644 --- a/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c +++ b/target/linux/adm5120/files/arch/mips/adm5120/boards/mikrotik.c @@ -42,8 +42,8 @@ #include <adm5120_nand.h> #include <adm5120_board.h> #include <adm5120_platform.h> -#include <adm5120_cf.h> #include <adm5120_info.h> + #include <prom/routerboot.h> #define RB1XX_NAND_CHIP_DELAY 25 @@ -127,8 +127,8 @@ static struct resource rb150_nand_resource[] = { static struct resource rb153_cf_resources[] = { { .name = "cf_membase", - .start = ADM5120_EXTIO0_BASE, - .end = ADM5120_EXTIO0_BASE + ADM5120_MPMC_SIZE-1 , + .start = ADM5120_EXTIO1_BASE, + .end = ADM5120_EXTIO1_BASE + ADM5120_EXTIO1_SIZE-1 , .flags = IORESOURCE_MEM }, { .name = "cf_irq", @@ -138,16 +138,11 @@ static struct resource rb153_cf_resources[] = { } }; -static struct cf_device rb153_cf_data = { - .gpio_pin = ADM5120_GPIO_PIN4 -}; - static struct platform_device rb153_cf_device = { - .name = "rb153-cf", + .name = "pata-rb153-cf", .id = -1, .resource = rb153_cf_resources, .num_resources = ARRAY_SIZE(rb153_cf_resources), - .dev.platform_data = &rb153_cf_data, }; static struct platform_device *rb153_devices[] __initdata = { @@ -223,7 +218,7 @@ static void rb150_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, static void __init rb1xx_mac_setup(void) { int i, j; - + for (i = 0; i < rb_hs.mac_count; i++) { for (j = 0; j < RB_MAC_SIZE; j++) adm5120_eth_macs[i][j] = rb_hs.macs[i][j]; @@ -247,6 +242,9 @@ static void __init rb1xx_flash_setup(void) static void __init rb153_cf_setup(void) { + /* enable CSX1:INTX1 on GPIO 3:4 for the CF slot */ + adm5120_gpio_csx1_enable(); + gpio_request(RB153_GPIO_CF_RDY, "cf-ready"); gpio_direction_input(RB153_GPIO_CF_RDY); gpio_request(RB153_GPIO_CF_WT, "cf-wait"); diff --git a/target/linux/adm5120/files/drivers/ata/pata_rb153_cf.c b/target/linux/adm5120/files/drivers/ata/pata_rb153_cf.c new file mode 100644 index 000000000..16ec6762f --- /dev/null +++ b/target/linux/adm5120/files/drivers/ata/pata_rb153_cf.c @@ -0,0 +1,303 @@ +/* + * A low-level PATA driver to handle a Compact Flash connected on the + * Mikrotik's RouterBoard 153 board. + * + * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org> + * + * This file was based on: drivers/ata/pata_ixp4xx_cf.c + * Copyright (C) 2006-07 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * Also was based on the driver for Linux 2.4.xx published by Mikrotik for + * their RouterBoard 1xx and 5xx series devices. The original Mikrotik code + * seems not to have a license. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include <linux/libata.h> +#include <scsi/scsi_host.h> + +#include <asm/gpio.h> + +#define DRV_NAME "pata-rb153-cf" +#define DRV_VERSION "0.1" +#define DRV_DESC "PATA driver for RouterBOARD 153 Compact Flash" + +#define RB153_CF_MAXPORTS 1 +#define RB153_CF_IO_DELAY 100 + +#define RB153_CF_REG_CMD 0x0800 +#define RB153_CF_REG_CTRL 0x080E +#define RB153_CF_REG_DATA 0x0C00 + +struct rb153_cf_info { + void __iomem *iobase; + unsigned int gpio_line; + int error; +}; + +/* ------------------------------------------------------------------------ */ + +static inline void rb153_pata_finish_io(struct ata_port *ap) +{ + struct ata_host *ah = ap->host; + + ata_altstatus(ap); + ndelay(RB153_CF_IO_DELAY); + + set_irq_type(ah->irq, IRQ_TYPE_LEVEL_HIGH); +} + +static void rb153_pata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + rb153_pata_finish_io(ap); +} + +static void rb153_pata_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + unsigned int i; + + if (write_data) { + for (i = 0; i < buflen; i++) + writeb(buf[i], ap->ioaddr.data_addr); + } else { + for (; buflen > 0; buflen--) + buf[i] = readb(ap->ioaddr.data_addr); + } + + rb153_pata_finish_io(ap); +} + +static void rb153_pata_thaw(struct ata_port *ap) +{ + struct rb153_cf_info *info = ap->host->private_data; + + info->error = 0; +} + +static irqreturn_t rb153_pata_irq_handler(int irq, void *dev_instance) +{ + struct ata_host *ah = dev_instance; + struct rb153_cf_info *info = ah->private_data; + + if (gpio_get_value(info->gpio_line)) { + set_irq_type(ah->irq, IRQ_TYPE_LEVEL_LOW); + if (!info->error) + ata_interrupt(irq, dev_instance); + } else { + set_irq_type(ah->irq, IRQ_TYPE_LEVEL_HIGH); + } + + return IRQ_HANDLED; +} + +static void rb153_pata_irq_clear(struct ata_port *ap) +{ +} + +static int rb153_pata_port_start(struct ata_port *ap) +{ + return 0; +} + +static struct ata_port_operations rb153_pata_port_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + + .exec_command = rb153_pata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .data_xfer = rb153_pata_data_xfer, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .thaw = rb153_pata_thaw, + .error_handler = ata_bmdma_error_handler, + + .irq_handler = rb153_pata_irq_handler, + .irq_clear = rb153_pata_irq_clear, + .irq_on = ata_irq_on, + + .port_start = rb153_pata_port_start, +}; + +/* ------------------------------------------------------------------------ */ + +static struct scsi_host_template rb153_pata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, + .proc_name = DRV_NAME, + + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .dma_boundary = ATA_DMA_BOUNDARY, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, +}; + +/* ------------------------------------------------------------------------ */ + +static void rb153_pata_setup_ports(struct ata_host *ah) +{ + struct rb153_cf_info *info = ah->private_data; + struct ata_port *ap; + struct ata_ioports *iop; + + ap = ah->ports[0]; + iop = &ap->ioaddr; + + ap->ops = &rb153_pata_port_ops; + ap->pio_mask = 0x1f; /* PIO4 */ + ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY; + + iop->cmd_addr = info->iobase + RB153_CF_REG_CMD; + iop->ctl_addr = info->iobase + RB153_CF_REG_CTRL; + iop->altstatus_addr = info->iobase + RB153_CF_REG_CTRL; + iop->data_addr = info->iobase + RB153_CF_REG_DATA; + + ata_std_ports(iop); +} + +static __devinit int rb153_pata_driver_probe(struct platform_device *pdev) +{ + unsigned int irq; + int gpio; + struct resource *res; + struct ata_host *ah; + struct rb153_cf_info *info; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no IOMEM resource found\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + return -ENOENT; + } + + gpio = irq_to_gpio(irq); + if (gpio < 0) { + dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq); + return -ENOENT; + } + + ret = gpio_request(gpio, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "GPIO request failed\n"); + return ret; + } + + /* allocate host */ + ah = ata_host_alloc(&pdev->dev, RB153_CF_MAXPORTS); + if (!ah) + return -ENOMEM; + + platform_set_drvdata(pdev, ah); + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ah->private_data = info; + + info->iobase = devm_ioremap_nocache(&pdev->dev, res->start, + res->end - res->start + 1); + if (!info->iobase) + return -ENOMEM; + + ret = gpio_direction_input(gpio); + if (ret) { + dev_err(&pdev->dev, "unable to set GPIO direction, err=%d\n", + ret); + goto err_free_gpio; + } + + rb153_pata_setup_ports(ah); + + ret = ata_host_activate(ah, irq, ata_interrupt, IRQF_TRIGGER_HIGH, + &rb153_pata_sht); + if (ret) + goto err_free_gpio; + + return 0; + +err_free_gpio: + gpio_free(gpio); + + return ret; +} + +static __devexit int rb153_pata_driver_remove(struct platform_device *pdev) +{ + struct ata_host *ah = platform_get_drvdata(pdev); + struct rb153_cf_info *info = ah->private_data; + + ata_host_detach(ah); + gpio_free(info->gpio_line); + + return 0; +} + +static struct platform_driver rb153_pata_platform_driver = { + .probe = rb153_pata_driver_probe, + .remove = __devexit_p(rb153_pata_driver_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +/* ------------------------------------------------------------------------ */ + +#define DRV_INFO DRV_DESC " version " DRV_VERSION + +static int __init rb153_pata_module_init(void) +{ + printk(KERN_INFO DRV_INFO "\n"); + + return platform_driver_register(&rb153_pata_platform_driver); +} + +static void __exit rb153_pata_module_exit(void) +{ + platform_driver_unregister(&rb153_pata_platform_driver); +} + +MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); + +module_init(rb153_pata_module_init); +module_exit(rb153_pata_module_exit); diff --git a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_defs.h b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_defs.h index 2f92a4564..42e951379 100644 --- a/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_defs.h +++ b/target/linux/adm5120/files/include/asm-mips/mach-adm5120/adm5120_defs.h @@ -29,29 +29,32 @@ #define ADM5120_SDRAM0_BASE 0x00000000 #define ADM5120_SDRAM1_BASE 0x01000000 #define ADM5120_SRAM1_BASE 0x10000000 -#define ADM5120_NAND_BASE ADM5120_SRAM1_BASE #define ADM5120_EXTIO0_BASE 0x10C00000 +#define ADM5120_EXTIO0_SIZE 0x00200000 +#define ADM5120_EXTIO1_BASE 0x10E00000 +#define ADM5120_EXTIO1_SIZE 0x00200000 #define ADM5120_MPMC_BASE 0x11000000 +#define ADM5120_MPMC_SIZE 0x00200000 #define ADM5120_USBC_BASE 0x11200000 +#define ADM5120_USBC_SIZE 0x00200000 #define ADM5120_PCIMEM_BASE 0x11400000 +#define ADM5120_PCIMEM_SIZE 0x00100000 #define ADM5120_PCIIO_BASE 0x11500000 +#define ADM5120_PCIIO_SIZE 0x000FFFF0 #define ADM5120_PCICFG_ADDR 0x115FFFF0 #define ADM5120_PCICFG_DATA 0x115FFFF8 +#define ADM5120_PCICFG_SIZE 0x00000010 #define ADM5120_SWITCH_BASE 0x12000000 +#define ADM5120_SWITCH_SIZE 0x00200000 #define ADM5120_INTC_BASE 0x12200000 +#define ADM5120_INTC_SIZE 0x00200000 #define ADM5120_UART0_BASE 0x12600000 #define ADM5120_UART1_BASE 0x12800000 +#define ADM5120_UART_SIZE 0x00200000 #define ADM5120_SRAM0_BASE 0x1FC00000 +#define ADM5120_NAND_BASE ADM5120_SRAM1_BASE #define ADM5120_NAND_SIZE 0xB -#define ADM5120_MPMC_SIZE 0x1000 -#define ADM5120_USBC_SIZE 0x84 -#define ADM5120_PCIMEM_SIZE (ADM5120_PCIIO_BASE - ADM5120_PCIMEM_BASE) -#define ADM5120_PCIIO_SIZE (ADM5120_PCICFG_ADDR - ADM5120_PCIIO_BASE) -#define ADM5120_PCICFG_SIZE 0x10 -#define ADM5120_SWITCH_SIZE 0x114 -#define ADM5120_INTC_SIZE 0x28 -#define ADM5120_UART_SIZE 0x20 #define ADM5120_CLK_175 175000000 #define ADM5120_CLK_200 200000000 |