From d0eb060915646fbe64a4f3aa25ffc4110e994db2 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 8 Jan 2015 20:26:34 +0000 Subject: gemini: add ata driver Signed-off-by: Roman Yeryomin git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43885 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- target/linux/gemini/config-3.10 | 2 + .../linux/gemini/files/drivers/ata/pata_gemini.c | 234 +++++++++++++++++++++ .../gemini/patches-3.10/150-gemini-pata.patch | 192 +++++++++++++++++ 3 files changed, 428 insertions(+) create mode 100644 target/linux/gemini/files/drivers/ata/pata_gemini.c create mode 100644 target/linux/gemini/patches-3.10/150-gemini-pata.patch (limited to 'target') diff --git a/target/linux/gemini/config-3.10 b/target/linux/gemini/config-3.10 index fdddd10a56..c6bcff199f 100644 --- a/target/linux/gemini/config-3.10 +++ b/target/linux/gemini/config-3.10 @@ -16,6 +16,7 @@ CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_NR_BANKS=8 CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARPD is not set +CONFIG_ATA=y CONFIG_ATAGS=y # CONFIG_CACHE_L2X0 is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -129,6 +130,7 @@ CONFIG_OLD_SIGACTION=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PATA_GEMINI=y CONFIG_PCI=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PHYLIB=y diff --git a/target/linux/gemini/files/drivers/ata/pata_gemini.c b/target/linux/gemini/files/drivers/ata/pata_gemini.c new file mode 100644 index 0000000000..707e8703bf --- /dev/null +++ b/target/linux/gemini/files/drivers/ata/pata_gemini.c @@ -0,0 +1,234 @@ +/* + * Support for Gemini PATA + * + * Copyright (C) 2009 Janos Laube + * Copyright (C) 2010 Frederic Pecourt + * Copyright (C) 2011 Tobias Waldvogel + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Values of IOMUX + * 26:24 bits is "IDE IO Select" + * 111:100 - Reserved + * 011 - ata0 <-> sata0, sata1; bring out ata1 + * 010 - ata1 <-> sata1, sata0; bring out ata0 + * 001 - ata0 <-> sata0, ata1 <-> sata1; bring out ata1 + * 000 - ata0 <-> sata0, ata1 <-> sata1; bring out ata0 + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata-gemini" + +#define PATA_GEMINI_PORTS 1 + +#define PIO_TIMING_REG 0x10 +#define MDMA_TIMING_REG 0x11 +#define UDMA_TIMING0_REG 0x12 +#define UDMA_TIMING1_REG 0x13 +#define CLK_MOD_REG 0x14 + +#define CLK_MOD_66M_DEV0_BIT 0 +#define CLK_MOD_66M_DEV1_BIT 1 +#define CLK_MOD_UDMA_DEV0_BIT 4 +#define CLK_MOD_UDMA_DEV1_BIT 5 + +#define CLK_MOD_66M_DEV0 (1 << CLK_MOD_66M_DEV0_BIT) +#define CLK_MOD_66M_DEV1 (1 << CLK_MOD_66M_DEV1_BIT) +#define CLK_MOD_UDMA_DEV0 (1 << CLK_MOD_UDMA_DEV0_BIT) +#define CLK_MOD_UDMA_DEV1 (1 << CLK_MOD_UDMA_DEV1_BIT) + +#define SATA_ENABLE_PDEV_MASK 0x01 +#define SATA_ENABLE_PDEV_PM 0x02 +#define SATA_ENABLE_PDEV_ADDED 0x04 +#define SATA_ENABLE_PDEV_REMOVED 0x08 +#define SATA_ENABLE_SDEV_MASK 0x10 +#define SATA_ENABLE_SDEV_PM 0x20 +#define SATA_ENABLE_SDEV_ADDED 0x40 +#define SATA_ENABLE_SDEV_REMOVED 0x80 + +MODULE_AUTHOR("Janos Laube "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); + +static unsigned char PIO_TIMING[5] = { + 0xaa, 0xa3, 0xa1, 0x33, 0x31 +}; + +static unsigned char TIMING_MW_DMA[4][2] = { + { 0x44, 1 }, // 480 4.2 + { 0x42, 1 }, // 150 13.3 + { 0x31, 1 }, // 120 16.7 + { 0x21, 1 }, // 100 20 +}; + +static unsigned char TIMING_UDMA[7][2] = { + { 0x33, 0 }, //240 16.7 + { 0x31, 0 }, //160 25 + { 0x21, 0 }, //120 33.3 + { 0x21, 1 }, //90 44.4 + { 0x11, 1 }, //60 66.7 + { 0x11 | 0x80, 0 }, //40 100 + { 0x11 | 0x80, 1 }, //30 133 +}; + +static struct scsi_host_template pata_gemini_sht = { + ATA_NCQ_SHT(DRV_NAME), + .can_queue = 1, + .sg_tablesize = 128, + .dma_boundary = 0xffffU, +}; + +static void gemini_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + void __iomem *clk_reg = ap->ioaddr.bmdma_addr + CLK_MOD_REG; + void __iomem *tim_reg = ap->ioaddr.bmdma_addr + UDMA_TIMING0_REG; + unsigned short udma = adev->dma_mode; + unsigned short speed = udma; + unsigned short devno = adev->devno & 1; + unsigned short i; + u8 mod_udma_mask = 1 << (CLK_MOD_UDMA_DEV0_BIT + devno); + u8 mod_66m_mask = 1 << (CLK_MOD_66M_DEV0_BIT + devno); + u8 clk_mod; + u8 timing; + + clk_mod = ioread8(clk_reg); + clk_mod &= ~mod_udma_mask; + + if (speed & XFER_UDMA_0) { + i = speed & ~XFER_UDMA_0; + timing = TIMING_UDMA[i][0]; + clk_mod |= mod_udma_mask; + if (TIMING_UDMA[i][1]) + clk_mod |= mod_66m_mask; + } else { + i = speed & ~XFER_MW_DMA_0; + timing = TIMING_MW_DMA[i][0]; + clk_mod |= mod_udma_mask; + if (TIMING_MW_DMA[i][1]) + clk_mod |= mod_66m_mask; + } + + iowrite8(clk_mod, clk_reg); + iowrite8(timing, tim_reg + devno); + return; +} + +static void gemini_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + void __iomem *pio_reg = ap->ioaddr.bmdma_addr + PIO_TIMING_REG; + unsigned int pio = adev->pio_mode - XFER_PIO_0; + + iowrite8(PIO_TIMING[pio], pio_reg); +} + +unsigned int gemini_qc_issue(struct ata_queued_cmd *qc) +{ + ledtrig_ide_activity(); + return ata_bmdma_qc_issue(qc); +} + +static struct ata_port_operations pata_gemini_port_ops = { + .inherits = &ata_bmdma_port_ops, + .set_dmamode = gemini_set_dmamode, + .set_piomode = gemini_set_piomode, + .qc_issue = gemini_qc_issue, +}; + +static struct ata_port_info pata_gemini_portinfo = { + .flags = 0, + .udma_mask = ATA_UDMA6, + .pio_mask = ATA_PIO4, + .port_ops = &pata_gemini_port_ops, +}; + +static const struct ata_port_info *pata_gemini_ports = &pata_gemini_portinfo; + +static int pata_gemini_probe(struct platform_device *pdev) +{ + struct ata_host *host; + struct resource *res; + unsigned int irq, i; + void __iomem *mmio_base; + + /* standard bdma init */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pr_info(DRV_NAME ": irq %d, io base 0x%08x\n", irq, res->start); + + mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + + host = ata_host_alloc_pinfo(&pdev->dev, &pata_gemini_ports, 1); + if (!host) + return -ENOMEM; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; + + ioaddr->bmdma_addr = mmio_base; + ioaddr->cmd_addr = mmio_base + 0x20; + ioaddr->ctl_addr = mmio_base + 0x36; + ioaddr->altstatus_addr = ioaddr->ctl_addr; + ata_sff_std_ports(ioaddr); + host->ports[i]->cbl = ATA_CBL_SATA; + } + + return ata_host_activate(host, irq, ata_bmdma_interrupt, + IRQF_SHARED, &pata_gemini_sht); +} + +static int pata_gemini_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + ata_host_detach(host); + return 0; +} + +static struct platform_driver pata_gemini_driver = { + .probe = pata_gemini_probe, + .remove = pata_gemini_remove, + .driver.owner = THIS_MODULE, + .driver.name = DRV_NAME, +}; + +static int __init pata_gemini_module_init(void) +{ + return platform_driver_probe(&pata_gemini_driver, pata_gemini_probe); +} + +static void __exit pata_gemini_module_exit(void) +{ + platform_driver_unregister(&pata_gemini_driver); +} + +module_init(pata_gemini_module_init); +module_exit(pata_gemini_module_exit); diff --git a/target/linux/gemini/patches-3.10/150-gemini-pata.patch b/target/linux/gemini/patches-3.10/150-gemini-pata.patch new file mode 100644 index 0000000000..1f3f451337 --- /dev/null +++ b/target/linux/gemini/patches-3.10/150-gemini-pata.patch @@ -0,0 +1,192 @@ +--- a/arch/arm/mach-gemini/include/mach/global_reg.h ++++ b/arch/arm/mach-gemini/include/mach/global_reg.h +@@ -227,7 +227,13 @@ + #define USB0_PLUG_MINIB (1 << 29) + #define GMAC_GMII (1 << 28) + #define GMAC_1_ENABLE (1 << 27) +-/* TODO: define ATA/SATA bits */ ++/* 011 - ata0 <-> sata0, sata1; bring out ata1 ++ * 010 - ata1 <-> sata1, sata0; bring out ata0 ++ * 001 - ata0 <-> sata0, ata1 <-> sata1; bring out ata1 ++ * 000 - ata0 <-> sata0, ata1 <-> sata1; bring out ata0 */ ++#define IDE_IOMUX_MASK (7 << 24) ++#define IDE_IOMUX_SATA1_SATA0 (2 << 24) ++#define IDE_IOMUX_SATA0_SATA1 (3 << 24) + #define USB1_VBUS_ON (1 << 23) + #define USB0_VBUS_ON (1 << 22) + #define APB_CLKOUT_ENABLE (1 << 21) +--- a/arch/arm/mach-gemini/irq.c 2013-02-19 13:38:13.263948000 +0100 ++++ b/arch/arm/mach-gemini/irq.c 2013-02-19 18:24:02.912997292 +0100 +@@ -88,6 +88,9 @@ + irq_set_handler(i, handle_edge_irq); + mode |= 1 << i; + level |= 1 << i; ++ } else if (i >= IRQ_IDE0 && i <= IRQ_IDE1) { ++ irq_set_handler(i, handle_edge_irq); ++ mode |= 1 << i; + } else { + irq_set_handler(i, handle_level_irq); + } +--- a/arch/arm/mach-gemini/common.h ++++ b/arch/arm/mach-gemini/common.h +@@ -29,6 +29,7 @@ + extern int platform_register_watchdog(void); + extern int platform_register_ethernet(struct gemini_gmac_platform_data *pdata); + extern int platform_register_usb(unsigned int id); ++extern int platform_register_pata(unsigned int id); + + extern void gemini_restart(char mode, const char *cmd); + +--- a/arch/arm/mach-gemini/devices.c ++++ b/arch/arm/mach-gemini/devices.c +@@ -249,3 +249,67 @@ + return platform_device_register(&usb_device[id]); + } + ++static u64 pata_gemini_dmamask0 = 0xffffffffUL; ++static u64 pata_gemini_dmamask1 = 0xffffffffUL; ++ ++static struct resource pata_gemini_resources0[] = ++{ ++ [0] = { ++ .start = GEMINI_IDE0_BASE, ++ .end = GEMINI_IDE0_BASE + 0x40, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_IDE0, ++ .end = IRQ_IDE0, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct resource pata_gemini_resources1[] = ++{ ++ [0] = { ++ .start = GEMINI_IDE1_BASE, ++ .end = GEMINI_IDE1_BASE + 0x40, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_IDE1, ++ .end = IRQ_IDE1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device pata_gemini_devices[] = ++{ ++ { ++ .name = "pata-gemini", ++ .id = 0, ++ .dev = ++ { ++ .dma_mask = &pata_gemini_dmamask0, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(pata_gemini_resources0), ++ .resource = pata_gemini_resources0, ++ }, ++ { ++ .name = "pata-gemini", ++ .id = 1, ++ .dev = ++ { ++ .dma_mask = &pata_gemini_dmamask1, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(pata_gemini_resources1), ++ .resource = pata_gemini_resources1, ++ }, ++}; ++ ++int __init platform_register_pata(unsigned int id) ++{ ++ if (id > 1) ++ return -EINVAL; ++ ++ return platform_device_register(&pata_gemini_devices[id]); ++} +--- a/arch/arm/mach-gemini/mm.c ++++ b/arch/arm/mach-gemini/mm.c +@@ -24,6 +24,11 @@ + .length = SZ_512K, + .type = MT_DEVICE, + }, { ++ .virtual = (unsigned long)IO_ADDRESS(GEMINI_SATA_BASE), ++ .pfn = __phys_to_pfn(GEMINI_SATA_BASE), ++ .length = SZ_512K, ++ .type = MT_DEVICE, ++ }, { + .virtual = (unsigned long)IO_ADDRESS(GEMINI_UART_BASE), + .pfn = __phys_to_pfn(GEMINI_UART_BASE), + .length = SZ_512K, +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -433,6 +433,16 @@ config PATA_EFAR + + If unsure, say N. + ++config PATA_GEMINI ++ tristate "Gemini PATA support (Experimental)" ++ depends on ARCH_GEMINI ++ help ++ This option enables support for the Gemini PATA-Controller. ++ Note that the Gemini SoC has no native SATA-Controller but an ++ onboard PATA-SATA bridge. ++ ++ If unsure, say N. ++ + config PATA_HPT366 + tristate "HPT 366/368 PATA support" + depends on PCI +--- a/drivers/ata/Makefile ++++ b/drivers/ata/Makefile +@@ -45,6 +45,7 @@ + obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o + obj-$(CONFIG_PATA_EFAR) += pata_efar.o + obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o ++obj-$(CONFIG_PATA_GEMINI) += pata_gemini.o + obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o + obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o + obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o +--- a/arch/arm/mach-gemini/board-nas4220b.c ++++ b/arch/arm/mach-gemini/board-nas4220b.c +@@ -146,11 +146,28 @@ + GLOBAL_MISC_CTRL)); + } + ++static void __init sata_ib4220b_init(void) ++{ ++ unsigned val; ++ ++ val = readl((void __iomem*)(IO_ADDRESS(GEMINI_GLOBAL_BASE) + ++ GLOBAL_MISC_CTRL)); ++ val &= ~(IDE_IOMUX_MASK | PFLASH_PADS_DISABLE); ++ val |= IDE_PADS_ENABLE; ++ writel(val, (void __iomem*)(IO_ADDRESS(GEMINI_GLOBAL_BASE) + ++ GLOBAL_MISC_CTRL)); ++ ++ /* enabling ports for presence detection, master only */ ++ writel(0x00000001, (void __iomem*)(IO_ADDRESS(GEMINI_SATA_BASE) + 0x18)); ++ writel(0x00000001, (void __iomem*)(IO_ADDRESS(GEMINI_SATA_BASE) + 0x1c)); ++} ++ + static void __init ib4220b_init(void) + { + gemini_gpio_init(); + ib4220b_gmac_init(); + usb_ib4220b_init(); ++ sata_ib4220b_init(); + platform_register_uart(); + platform_register_pflash(SZ_16M, NULL, 0); + platform_device_register(&ib4220b_led_device); +@@ -161,6 +178,8 @@ + platform_register_ethernet(&ib4220b_gmac_data); + platform_register_usb(0); + platform_register_usb(1); ++ platform_register_pata(0); ++ platform_register_pata(1); + } + + MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B") -- cgit v1.2.3