1/* 2 * TX4938 internal IDE driver 3 * Based on tx4939ide.c. 4 * 5 * This file is subject to the terms and conditions of the GNU General Public 6 * License. See the file "COPYING" in the main directory of this archive 7 * for more details. 8 * 9 * (C) Copyright TOSHIBA CORPORATION 2005-2007 10 */ 11 12#include <linux/module.h> 13#include <linux/types.h> 14#include <linux/ide.h> 15#include <linux/init.h> 16#include <linux/platform_device.h> 17#include <linux/io.h> 18 19#include <asm/ide.h> 20#include <asm/txx9/tx4938.h> 21 22static void tx4938ide_tune_ebusc(unsigned int ebus_ch, 23 unsigned int gbus_clock, 24 u8 pio) 25{ 26 struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); 27 u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]); 28 unsigned int sp = (cr >> 4) & 3; 29 unsigned int clock = gbus_clock / (4 - sp); 30 unsigned int cycle = 1000000000 / clock; 31 unsigned int shwt; 32 int wt; 33 34 /* Minimum DIOx- active time */ 35 wt = DIV_ROUND_UP(t->act8b, cycle) - 2; 36 /* IORDY setup time: 35ns */ 37 wt = max_t(int, wt, DIV_ROUND_UP(35, cycle)); 38 /* actual wait-cycle is max(wt & ~1, 1) */ 39 if (wt > 2 && (wt & 1)) 40 wt++; 41 wt &= ~1; 42 /* Address-valid to DIOR/DIOW setup */ 43 shwt = DIV_ROUND_UP(t->setup, cycle); 44 45 /* -DIOx recovery time (SHWT * 4) and cycle time requirement */ 46 while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle) 47 shwt++; 48 if (shwt > 7) { 49 pr_warning("tx4938ide: SHWT violation (%d)\n", shwt); 50 shwt = 7; 51 } 52 pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n", 53 ebus_ch, cycle, wt, shwt); 54 55 __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt, 56 &tx4938_ebuscptr->cr[ebus_ch]); 57} 58 59static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 60{ 61 struct tx4938ide_platform_info *pdata = hwif->dev->platform_data; 62 u8 safe = drive->pio_mode - XFER_PIO_0; 63 ide_drive_t *pair; 64 65 pair = ide_get_pair_dev(drive); 66 if (pair) 67 safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); 68 tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe); 69} 70 71#ifdef __BIG_ENDIAN 72 73/* custom iops (independent from SWAP_IO_SPACE) */ 74static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 75 void *buf, unsigned int len) 76{ 77 unsigned long port = drive->hwif->io_ports.data_addr; 78 unsigned short *ptr = buf; 79 unsigned int count = (len + 1) / 2; 80 81 while (count--) 82 *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); 83 __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 84} 85 86static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 87 void *buf, unsigned int len) 88{ 89 unsigned long port = drive->hwif->io_ports.data_addr; 90 unsigned short *ptr = buf; 91 unsigned int count = (len + 1) / 2; 92 93 while (count--) { 94 __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); 95 ptr++; 96 } 97 __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 98} 99 100static const struct ide_tp_ops tx4938ide_tp_ops = { 101 .exec_command = ide_exec_command, 102 .read_status = ide_read_status, 103 .read_altstatus = ide_read_altstatus, 104 .write_devctl = ide_write_devctl, 105 106 .dev_select = ide_dev_select, 107 .tf_load = ide_tf_load, 108 .tf_read = ide_tf_read, 109 110 .input_data = tx4938ide_input_data_swap, 111 .output_data = tx4938ide_output_data_swap, 112}; 113 114#endif /* __BIG_ENDIAN */ 115 116static const struct ide_port_ops tx4938ide_port_ops = { 117 .set_pio_mode = tx4938ide_set_pio_mode, 118}; 119 120static const struct ide_port_info tx4938ide_port_info __initdata = { 121 .port_ops = &tx4938ide_port_ops, 122#ifdef __BIG_ENDIAN 123 .tp_ops = &tx4938ide_tp_ops, 124#endif 125 .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, 126 .pio_mask = ATA_PIO5, 127 .chipset = ide_generic, 128}; 129 130static int __init tx4938ide_probe(struct platform_device *pdev) 131{ 132 struct ide_hw hw, *hws[] = { &hw }; 133 struct ide_host *host; 134 struct resource *res; 135 struct tx4938ide_platform_info *pdata = pdev->dev.platform_data; 136 int irq, ret, i; 137 unsigned long mapbase, mapctl; 138 struct ide_port_info d = tx4938ide_port_info; 139 140 irq = platform_get_irq(pdev, 0); 141 if (irq < 0) 142 return -ENODEV; 143 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 144 if (!res) 145 return -ENODEV; 146 147 if (!devm_request_mem_region(&pdev->dev, res->start, 148 resource_size(res), "tx4938ide")) 149 return -EBUSY; 150 mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, 151 8 << pdata->ioport_shift); 152 mapctl = (unsigned long)devm_ioremap(&pdev->dev, 153 res->start + 0x10000 + 154 (6 << pdata->ioport_shift), 155 1 << pdata->ioport_shift); 156 if (!mapbase || !mapctl) 157 return -EBUSY; 158 159 memset(&hw, 0, sizeof(hw)); 160 if (pdata->ioport_shift) { 161 unsigned long port = mapbase; 162 unsigned long ctl = mapctl; 163 164 hw.io_ports_array[0] = port; 165#ifdef __BIG_ENDIAN 166 port++; 167 ctl++; 168#endif 169 for (i = 1; i <= 7; i++) 170 hw.io_ports_array[i] = 171 port + (i << pdata->ioport_shift); 172 hw.io_ports.ctl_addr = ctl; 173 } else 174 ide_std_init_ports(&hw, mapbase, mapctl); 175 hw.irq = irq; 176 hw.dev = &pdev->dev; 177 178 pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n", 179 mapbase, mapctl, hw.irq); 180 if (pdata->gbus_clock) 181 tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0); 182 else 183 d.port_ops = NULL; 184 ret = ide_host_add(&d, hws, 1, &host); 185 if (!ret) 186 platform_set_drvdata(pdev, host); 187 return ret; 188} 189 190static int __exit tx4938ide_remove(struct platform_device *pdev) 191{ 192 struct ide_host *host = platform_get_drvdata(pdev); 193 194 ide_host_remove(host); 195 return 0; 196} 197 198static struct platform_driver tx4938ide_driver = { 199 .driver = { 200 .name = "tx4938ide", 201 .owner = THIS_MODULE, 202 }, 203 .remove = __exit_p(tx4938ide_remove), 204}; 205 206static int __init tx4938ide_init(void) 207{ 208 return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe); 209} 210 211static void __exit tx4938ide_exit(void) 212{ 213 platform_driver_unregister(&tx4938ide_driver); 214} 215 216module_init(tx4938ide_init); 217module_exit(tx4938ide_exit); 218 219MODULE_DESCRIPTION("TX4938 internal IDE driver"); 220MODULE_LICENSE("GPL"); 221MODULE_ALIAS("platform:tx4938ide"); 222