Blame view

drivers/ide/tx4938ide.c 5.74 KB
28502848f   Atsushi Nemoto   ide: Add tx4938id...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * TX4938 internal IDE driver
   * Based on tx4939ide.c.
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
   *
   * (C) Copyright TOSHIBA CORPORATION 2005-2007
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/ide.h>
  #include <linux/init.h>
  #include <linux/platform_device.h>
  #include <linux/io.h>
15a453a95   Bartlomiej Zolnierkiewicz   ide: include <asm...
18
19
  
  #include <asm/ide.h>
28502848f   Atsushi Nemoto   ide: Add tx4938id...
20
21
22
23
24
25
26
27
28
29
30
  #include <asm/txx9/tx4938.h>
  
  static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
  				 unsigned int gbus_clock,
  				 u8 pio)
  {
  	struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
  	u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]);
  	unsigned int sp = (cr >> 4) & 3;
  	unsigned int clock = gbus_clock / (4 - sp);
  	unsigned int cycle = 1000000000 / clock;
7afa05350   Atsushi Nemoto   tx4938ide: Avoid ...
31
32
  	unsigned int shwt;
  	int wt;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
33
34
35
36
  
  	/* Minimum DIOx- active time */
  	wt = DIV_ROUND_UP(t->act8b, cycle) - 2;
  	/* IORDY setup time: 35ns */
7afa05350   Atsushi Nemoto   tx4938ide: Avoid ...
37
  	wt = max_t(int, wt, DIV_ROUND_UP(35, cycle));
28502848f   Atsushi Nemoto   ide: Add tx4938id...
38
39
40
41
42
43
  	/* actual wait-cycle is max(wt & ~1, 1) */
  	if (wt > 2 && (wt & 1))
  		wt++;
  	wt &= ~1;
  	/* Address-valid to DIOR/DIOW setup */
  	shwt = DIV_ROUND_UP(t->setup, cycle);
630a8b250   Atsushi Nemoto   tx4938ide: Check ...
44
45
46
47
48
49
50
51
  	/* -DIOx recovery time (SHWT * 4) and cycle time requirement */
  	while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle)
  		shwt++;
  	if (shwt > 7) {
  		pr_warning("tx4938ide: SHWT violation (%d)
  ", shwt);
  		shwt = 7;
  	}
28502848f   Atsushi Nemoto   ide: Add tx4938id...
52
53
54
  	pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d
  ",
  		 ebus_ch, cycle, wt, shwt);
630a8b250   Atsushi Nemoto   tx4938ide: Check ...
55
  	__raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
56
57
  		     &tx4938_ebuscptr->cr[ebus_ch]);
  }
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
58
  static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
28502848f   Atsushi Nemoto   ide: Add tx4938id...
59
  {
28502848f   Atsushi Nemoto   ide: Add tx4938id...
60
  	struct tx4938ide_platform_info *pdata = hwif->dev->platform_data;
e085b3cae   Bartlomiej Zolnierkiewicz   ide: change ->set...
61
  	u8 safe = drive->pio_mode - XFER_PIO_0;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
62
63
64
65
  	ide_drive_t *pair;
  
  	pair = ide_get_pair_dev(drive);
  	if (pair)
cd078af65   Atsushi Nemoto   tx493xide: use mi...
66
  		safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
28502848f   Atsushi Nemoto   ide: Add tx4938id...
67
68
69
70
71
72
  	tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
  }
  
  #ifdef __BIG_ENDIAN
  
  /* custom iops (independent from SWAP_IO_SPACE) */
adb1af980   Bartlomiej Zolnierkiewicz   ide: pass command...
73
  static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
74
75
76
77
78
79
80
81
  				void *buf, unsigned int len)
  {
  	unsigned long port = drive->hwif->io_ports.data_addr;
  	unsigned short *ptr = buf;
  	unsigned int count = (len + 1) / 2;
  
  	while (count--)
  		*ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
f26f6ceac   Atsushi Nemoto   tx493[89]ide: Fix...
82
  	__ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
28502848f   Atsushi Nemoto   ide: Add tx4938id...
83
  }
adb1af980   Bartlomiej Zolnierkiewicz   ide: pass command...
84
  static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
85
86
87
88
89
90
91
92
93
94
  				void *buf, unsigned int len)
  {
  	unsigned long port = drive->hwif->io_ports.data_addr;
  	unsigned short *ptr = buf;
  	unsigned int count = (len + 1) / 2;
  
  	while (count--) {
  		__raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
  		ptr++;
  	}
f26f6ceac   Atsushi Nemoto   tx493[89]ide: Fix...
95
  	__ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
28502848f   Atsushi Nemoto   ide: Add tx4938id...
96
97
98
99
100
101
  }
  
  static const struct ide_tp_ops tx4938ide_tp_ops = {
  	.exec_command		= ide_exec_command,
  	.read_status		= ide_read_status,
  	.read_altstatus		= ide_read_altstatus,
ecf3a31d2   Sergei Shtylyov   ide: turn set_irq...
102
  	.write_devctl		= ide_write_devctl,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
103

abb596b25   Sergei Shtylyov   ide: turn selectp...
104
  	.dev_select		= ide_dev_select,
d68bab503   Atsushi Nemoto   tx493[89]ide: Rem...
105
106
  	.tf_load		= ide_tf_load,
  	.tf_read		= ide_tf_read,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
107
108
109
110
111
112
113
114
  
  	.input_data		= tx4938ide_input_data_swap,
  	.output_data		= tx4938ide_output_data_swap,
  };
  
  #endif	/* __BIG_ENDIAN */
  
  static const struct ide_port_ops tx4938ide_port_ops = {
3ee86dcdd   Bartlomiej Zolnierkiewicz   tx493x: fix inden...
115
  	.set_pio_mode		= tx4938ide_set_pio_mode,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
116
117
118
  };
  
  static const struct ide_port_info tx4938ide_port_info __initdata = {
3ee86dcdd   Bartlomiej Zolnierkiewicz   tx493x: fix inden...
119
  	.port_ops		= &tx4938ide_port_ops,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
120
  #ifdef __BIG_ENDIAN
3ee86dcdd   Bartlomiej Zolnierkiewicz   tx493x: fix inden...
121
  	.tp_ops			= &tx4938ide_tp_ops,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
122
  #endif
3ee86dcdd   Bartlomiej Zolnierkiewicz   tx493x: fix inden...
123
124
  	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
  	.pio_mask		= ATA_PIO5,
b1d249e84   Bartlomiej Zolnierkiewicz   ide: remove chips...
125
  	.chipset		= ide_generic,
28502848f   Atsushi Nemoto   ide: Add tx4938id...
126
127
128
129
  };
  
  static int __init tx4938ide_probe(struct platform_device *pdev)
  {
9f36d3143   Bartlomiej Zolnierkiewicz   ide: remove hw_re...
130
  	struct ide_hw hw, *hws[] = { &hw };
28502848f   Atsushi Nemoto   ide: Add tx4938id...
131
132
133
134
  	struct ide_host *host;
  	struct resource *res;
  	struct tx4938ide_platform_info *pdata = pdev->dev.platform_data;
  	int irq, ret, i;
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
135
  	unsigned long mapbase, mapctl;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
136
137
138
139
140
141
142
143
144
145
  	struct ide_port_info d = tx4938ide_port_info;
  
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0)
  		return -ENODEV;
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -ENODEV;
  
  	if (!devm_request_mem_region(&pdev->dev, res->start,
849209054   H Hartley Sweeten   drivers/ide/tx493...
146
  				     resource_size(res), "tx4938ide"))
28502848f   Atsushi Nemoto   ide: Add tx4938id...
147
148
  		return -EBUSY;
  	mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
149
150
151
152
153
154
  					      8 << pdata->ioport_shift);
  	mapctl = (unsigned long)devm_ioremap(&pdev->dev,
  					     res->start + 0x10000 +
  					     (6 << pdata->ioport_shift),
  					     1 << pdata->ioport_shift);
  	if (!mapbase || !mapctl)
28502848f   Atsushi Nemoto   ide: Add tx4938id...
155
156
157
158
159
  		return -EBUSY;
  
  	memset(&hw, 0, sizeof(hw));
  	if (pdata->ioport_shift) {
  		unsigned long port = mapbase;
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
160
  		unsigned long ctl = mapctl;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
161
162
163
164
  
  		hw.io_ports_array[0] = port;
  #ifdef __BIG_ENDIAN
  		port++;
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
165
  		ctl++;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
166
167
168
169
  #endif
  		for (i = 1; i <= 7; i++)
  			hw.io_ports_array[i] =
  				port + (i << pdata->ioport_shift);
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
170
  		hw.io_ports.ctl_addr = ctl;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
171
  	} else
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
172
  		ide_std_init_ports(&hw, mapbase, mapctl);
28502848f   Atsushi Nemoto   ide: Add tx4938id...
173
174
  	hw.irq = irq;
  	hw.dev = &pdev->dev;
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
175
176
177
  	pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)
  ",
  		mapbase, mapctl, hw.irq);
28502848f   Atsushi Nemoto   ide: Add tx4938id...
178
179
180
181
  	if (pdata->gbus_clock)
  		tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
  	else
  		d.port_ops = NULL;
dca398305   Bartlomiej Zolnierkiewicz   ide: pass number ...
182
  	ret = ide_host_add(&d, hws, 1, &host);
9d4eb0a33   Atsushi Nemoto   tx4938ide: Do not...
183
184
185
  	if (!ret)
  		platform_set_drvdata(pdev, host);
  	return ret;
28502848f   Atsushi Nemoto   ide: Add tx4938id...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  }
  
  static int __exit tx4938ide_remove(struct platform_device *pdev)
  {
  	struct ide_host *host = platform_get_drvdata(pdev);
  
  	ide_host_remove(host);
  	return 0;
  }
  
  static struct platform_driver tx4938ide_driver = {
  	.driver		= {
  		.name	= "tx4938ide",
  		.owner	= THIS_MODULE,
  	},
  	.remove = __exit_p(tx4938ide_remove),
  };
  
  static int __init tx4938ide_init(void)
  {
  	return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe);
  }
  
  static void __exit tx4938ide_exit(void)
  {
  	platform_driver_unregister(&tx4938ide_driver);
  }
  
  module_init(tx4938ide_init);
  module_exit(tx4938ide_exit);
  
  MODULE_DESCRIPTION("TX4938 internal IDE driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:tx4938ide");