tx4938ide.c revision d68bab503e64e87c464c5a27a56877a04e4404b5
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_drive_t *drive, const u8 pio) 60{ 61 ide_hwif_t *hwif = drive->hwif; 62 struct tx4938ide_platform_info *pdata = hwif->dev->platform_data; 63 u8 safe = pio; 64 ide_drive_t *pair; 65 66 pair = ide_get_pair_dev(drive); 67 if (pair) 68 safe = min(safe, ide_get_best_pio_mode(pair, 255, 5)); 69 tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe); 70} 71 72#ifdef __BIG_ENDIAN 73 74/* custom iops (independent from SWAP_IO_SPACE) */ 75static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 76 void *buf, unsigned int len) 77{ 78 unsigned long port = drive->hwif->io_ports.data_addr; 79 unsigned short *ptr = buf; 80 unsigned int count = (len + 1) / 2; 81 82 while (count--) 83 *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); 84 __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 85} 86 87static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 88 void *buf, unsigned int len) 89{ 90 unsigned long port = drive->hwif->io_ports.data_addr; 91 unsigned short *ptr = buf; 92 unsigned int count = (len + 1) / 2; 93 94 while (count--) { 95 __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); 96 ptr++; 97 } 98 __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 99} 100 101static const struct ide_tp_ops tx4938ide_tp_ops = { 102 .exec_command = ide_exec_command, 103 .read_status = ide_read_status, 104 .read_altstatus = ide_read_altstatus, 105 .write_devctl = ide_write_devctl, 106 107 .dev_select = ide_dev_select, 108 .tf_load = ide_tf_load, 109 .tf_read = ide_tf_read, 110 111 .input_data = tx4938ide_input_data_swap, 112 .output_data = tx4938ide_output_data_swap, 113}; 114 115#endif /* __BIG_ENDIAN */ 116 117static const struct ide_port_ops tx4938ide_port_ops = { 118 .set_pio_mode = tx4938ide_set_pio_mode, 119}; 120 121static const struct ide_port_info tx4938ide_port_info __initdata = { 122 .port_ops = &tx4938ide_port_ops, 123#ifdef __BIG_ENDIAN 124 .tp_ops = &tx4938ide_tp_ops, 125#endif 126 .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, 127 .pio_mask = ATA_PIO5, 128 .chipset = ide_generic, 129}; 130 131static int __init tx4938ide_probe(struct platform_device *pdev) 132{ 133 hw_regs_t hw; 134 hw_regs_t *hws[] = { &hw, NULL, NULL, NULL }; 135 struct ide_host *host; 136 struct resource *res; 137 struct tx4938ide_platform_info *pdata = pdev->dev.platform_data; 138 int irq, ret, i; 139 unsigned long mapbase, mapctl; 140 struct ide_port_info d = tx4938ide_port_info; 141 142 irq = platform_get_irq(pdev, 0); 143 if (irq < 0) 144 return -ENODEV; 145 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 146 if (!res) 147 return -ENODEV; 148 149 if (!devm_request_mem_region(&pdev->dev, res->start, 150 res->end - res->start + 1, "tx4938ide")) 151 return -EBUSY; 152 mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, 153 8 << pdata->ioport_shift); 154 mapctl = (unsigned long)devm_ioremap(&pdev->dev, 155 res->start + 0x10000 + 156 (6 << pdata->ioport_shift), 157 1 << pdata->ioport_shift); 158 if (!mapbase || !mapctl) 159 return -EBUSY; 160 161 memset(&hw, 0, sizeof(hw)); 162 if (pdata->ioport_shift) { 163 unsigned long port = mapbase; 164 unsigned long ctl = mapctl; 165 166 hw.io_ports_array[0] = port; 167#ifdef __BIG_ENDIAN 168 port++; 169 ctl++; 170#endif 171 for (i = 1; i <= 7; i++) 172 hw.io_ports_array[i] = 173 port + (i << pdata->ioport_shift); 174 hw.io_ports.ctl_addr = ctl; 175 } else 176 ide_std_init_ports(&hw, mapbase, mapctl); 177 hw.irq = irq; 178 hw.dev = &pdev->dev; 179 180 pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n", 181 mapbase, mapctl, hw.irq); 182 if (pdata->gbus_clock) 183 tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0); 184 else 185 d.port_ops = NULL; 186 ret = ide_host_add(&d, hws, &host); 187 if (!ret) 188 platform_set_drvdata(pdev, host); 189 return ret; 190} 191 192static int __exit tx4938ide_remove(struct platform_device *pdev) 193{ 194 struct ide_host *host = platform_get_drvdata(pdev); 195 196 ide_host_remove(host); 197 return 0; 198} 199 200static struct platform_driver tx4938ide_driver = { 201 .driver = { 202 .name = "tx4938ide", 203 .owner = THIS_MODULE, 204 }, 205 .remove = __exit_p(tx4938ide_remove), 206}; 207 208static int __init tx4938ide_init(void) 209{ 210 return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe); 211} 212 213static void __exit tx4938ide_exit(void) 214{ 215 platform_driver_unregister(&tx4938ide_driver); 216} 217 218module_init(tx4938ide_init); 219module_exit(tx4938ide_exit); 220 221MODULE_DESCRIPTION("TX4938 internal IDE driver"); 222MODULE_LICENSE("GPL"); 223MODULE_ALIAS("platform:tx4938ide"); 224