Blame view

drivers/ata/pata_pxa.c 7.87 KB
c82ee6d3b   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
2
3
4
5
  /*
   * Generic PXA PATA driver
   *
   * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
6
7
8
9
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
10
11
12
13
  #include <linux/blkdev.h>
  #include <linux/ata.h>
  #include <linux/libata.h>
  #include <linux/platform_device.h>
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
14
  #include <linux/dmaengine.h>
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
15
16
17
18
  #include <linux/slab.h>
  #include <linux/completion.h>
  
  #include <scsi/scsi_host.h>
293b2da1b   Arnd Bergmann   ARM: pxa: move pl...
19
  #include <linux/platform_data/ata-pxa.h>
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
20
21
22
23
24
  
  #define DRV_NAME	"pata_pxa"
  #define DRV_VERSION	"0.1"
  
  struct pata_pxa_data {
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
25
26
  	struct dma_chan		*dma_chan;
  	dma_cookie_t		dma_cookie;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
27
28
29
30
  	struct completion	dma_done;
  };
  
  /*
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
31
   * DMA interrupt handler.
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
32
   */
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
33
  static void pxa_ata_dma_irq(void *d)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
34
  {
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
35
36
  	struct pata_pxa_data *pd = d;
  	enum dma_status status;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
37

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
38
39
40
  	status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, NULL);
  	if (status == DMA_ERROR || status == DMA_COMPLETE)
  		complete(&pd->dma_done);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
41
42
43
44
45
  }
  
  /*
   * Prepare taskfile for submission.
   */
95364f367   Jiri Slaby   ata: make qc_prep...
46
  static enum ata_completion_errors pxa_qc_prep(struct ata_queued_cmd *qc)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
47
48
  {
  	struct pata_pxa_data *pd = qc->ap->private_data;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
49
50
  	struct dma_async_tx_descriptor *tx;
  	enum dma_transfer_direction dir;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
51
52
  
  	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
95364f367   Jiri Slaby   ata: make qc_prep...
53
  		return AC_ERR_OK;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
54

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
55
56
57
58
59
60
  	dir = (qc->dma_dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
  	tx = dmaengine_prep_slave_sg(pd->dma_chan, qc->sg, qc->n_elem, dir,
  				     DMA_PREP_INTERRUPT);
  	if (!tx) {
  		ata_dev_err(qc->dev, "prep_slave_sg() failed
  ");
95364f367   Jiri Slaby   ata: make qc_prep...
61
  		return AC_ERR_OK;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
62
63
64
65
  	}
  	tx->callback = pxa_ata_dma_irq;
  	tx->callback_param = pd;
  	pd->dma_cookie = dmaengine_submit(tx);
95364f367   Jiri Slaby   ata: make qc_prep...
66
67
  
  	return AC_ERR_OK;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  }
  
  /*
   * Configure the DMA controller, load the DMA descriptors, but don't start the
   * DMA controller yet. Only issue the ATA command.
   */
  static void pxa_bmdma_setup(struct ata_queued_cmd *qc)
  {
  	qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
  }
  
  /*
   * Execute the DMA transfer.
   */
  static void pxa_bmdma_start(struct ata_queued_cmd *qc)
  {
  	struct pata_pxa_data *pd = qc->ap->private_data;
  	init_completion(&pd->dma_done);
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
86
  	dma_async_issue_pending(pd->dma_chan);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
87
88
89
90
91
92
93
94
  }
  
  /*
   * Wait until the DMA transfer completes, then stop the DMA controller.
   */
  static void pxa_bmdma_stop(struct ata_queued_cmd *qc)
  {
  	struct pata_pxa_data *pd = qc->ap->private_data;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
95
  	enum dma_status status;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
96

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
97
98
99
100
  	status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, NULL);
  	if (status != DMA_ERROR && status != DMA_COMPLETE &&
  	    wait_for_completion_timeout(&pd->dma_done, HZ))
  		ata_dev_err(qc->dev, "Timeout waiting for DMA completion!");
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
101

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
102
  	dmaengine_terminate_all(pd->dma_chan);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
103
104
105
106
107
108
109
110
111
112
  }
  
  /*
   * Read DMA status. The bmdma_stop() will take care of properly finishing the
   * DMA transfer so we always have DMA-complete interrupt here.
   */
  static unsigned char pxa_bmdma_status(struct ata_port *ap)
  {
  	struct pata_pxa_data *pd = ap->private_data;
  	unsigned char ret = ATA_DMA_INTR;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
113
114
  	struct dma_tx_state state;
  	enum dma_status status;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
115

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
116
117
  	status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, &state);
  	if (status != DMA_COMPLETE)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  		ret |= ATA_DMA_ERR;
  
  	return ret;
  }
  
  /*
   * No IRQ register present so we do nothing.
   */
  static void pxa_irq_clear(struct ata_port *ap)
  {
  }
  
  /*
   * Check for ATAPI DMA. ATAPI DMA is unsupported by this driver. It's still
   * unclear why ATAPI has DMA issues.
   */
  static int pxa_check_atapi_dma(struct ata_queued_cmd *qc)
  {
  	return -EOPNOTSUPP;
  }
  
  static struct scsi_host_template pxa_ata_sht = {
  	ATA_BMDMA_SHT(DRV_NAME),
  };
  
  static struct ata_port_operations pxa_ata_port_ops = {
  	.inherits		= &ata_bmdma_port_ops,
  	.cable_detect		= ata_cable_40wire,
  
  	.bmdma_setup		= pxa_bmdma_setup,
  	.bmdma_start		= pxa_bmdma_start,
  	.bmdma_stop		= pxa_bmdma_stop,
  	.bmdma_status		= pxa_bmdma_status,
  
  	.check_atapi_dma	= pxa_check_atapi_dma,
  
  	.sff_irq_clear		= pxa_irq_clear,
  
  	.qc_prep		= pxa_qc_prep,
  };
0ec249146   Greg Kroah-Hartman   Drivers: ata: rem...
158
  static int pxa_ata_probe(struct platform_device *pdev)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
159
160
161
162
163
164
165
166
  {
  	struct ata_host *host;
  	struct ata_port *ap;
  	struct pata_pxa_data *data;
  	struct resource *cmd_res;
  	struct resource *ctl_res;
  	struct resource *dma_res;
  	struct resource *irq_res;
61b8c345a   Jingoo Han   ata: use dev_get_...
167
  	struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
168
  	struct dma_slave_config	config;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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
220
221
222
  	int ret = 0;
  
  	/*
  	 * Resource validation, three resources are needed:
  	 *  - CMD port base address
  	 *  - CTL port base address
  	 *  - DMA port base address
  	 *  - IRQ pin
  	 */
  	if (pdev->num_resources != 4) {
  		dev_err(&pdev->dev, "invalid number of resources
  ");
  		return -EINVAL;
  	}
  
  	/*
  	 * CMD port base address
  	 */
  	cmd_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (unlikely(cmd_res == NULL))
  		return -EINVAL;
  
  	/*
  	 * CTL port base address
  	 */
  	ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  	if (unlikely(ctl_res == NULL))
  		return -EINVAL;
  
  	/*
  	 * DMA port base address
  	 */
  	dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
  	if (unlikely(dma_res == NULL))
  		return -EINVAL;
  
  	/*
  	 * IRQ pin
  	 */
  	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  	if (unlikely(irq_res == NULL))
  		return -EINVAL;
  
  	/*
  	 * Allocate the host
  	 */
  	host = ata_host_alloc(&pdev->dev, 1);
  	if (!host)
  		return -ENOMEM;
  
  	ap		= host->ports[0];
  	ap->ops		= &pxa_ata_port_ops;
  	ap->pio_mask	= ATA_PIO4;
  	ap->mwdma_mask	= ATA_MWDMA2;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  
  	ap->ioaddr.cmd_addr	= devm_ioremap(&pdev->dev, cmd_res->start,
  						resource_size(cmd_res));
  	ap->ioaddr.ctl_addr	= devm_ioremap(&pdev->dev, ctl_res->start,
  						resource_size(ctl_res));
  	ap->ioaddr.bmdma_addr	= devm_ioremap(&pdev->dev, dma_res->start,
  						resource_size(dma_res));
  
  	/*
  	 * Adjust register offsets
  	 */
  	ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
  	ap->ioaddr.data_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_DATA << pdata->reg_shift);
  	ap->ioaddr.error_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_ERR << pdata->reg_shift);
  	ap->ioaddr.feature_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_FEATURE << pdata->reg_shift);
  	ap->ioaddr.nsect_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_NSECT << pdata->reg_shift);
  	ap->ioaddr.lbal_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_LBAL << pdata->reg_shift);
  	ap->ioaddr.lbam_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_LBAM << pdata->reg_shift);
  	ap->ioaddr.lbah_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_LBAH << pdata->reg_shift);
  	ap->ioaddr.device_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_DEVICE << pdata->reg_shift);
  	ap->ioaddr.status_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_STATUS << pdata->reg_shift);
  	ap->ioaddr.command_addr	= ap->ioaddr.cmd_addr +
  					(ATA_REG_CMD << pdata->reg_shift);
  
  	/*
  	 * Allocate and load driver's internal data structure
  	 */
  	data = devm_kzalloc(&pdev->dev, sizeof(struct pata_pxa_data),
  								GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	ap->private_data = data;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
265

88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
266
267
268
269
270
271
272
  	memset(&config, 0, sizeof(config));
  	config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  	config.src_addr = dma_res->start;
  	config.dst_addr = dma_res->start;
  	config.src_maxburst = 32;
  	config.dst_maxburst = 32;
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
273
274
275
276
  
  	/*
  	 * Request the DMA channel
  	 */
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
277
  	data->dma_chan =
273340e8b   Robert Jarzmik   ata: pata_pxa: re...
278
  		dma_request_slave_channel(&pdev->dev, "data");
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
279
  	if (!data->dma_chan)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
280
  		return -EBUSY;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
281
282
283
284
285
286
  	ret = dmaengine_slave_config(data->dma_chan, &config);
  	if (ret < 0) {
  		dev_err(&pdev->dev, "dma configuration failed: %d
  ", ret);
  		return ret;
  	}
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
287
288
289
290
291
292
293
  
  	/*
  	 * Activate the ATA host
  	 */
  	ret = ata_host_activate(host, irq_res->start, ata_sff_interrupt,
  				pdata->irq_flags, &pxa_ata_sht);
  	if (ret)
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
294
  		dma_release_channel(data->dma_chan);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
295
296
297
  
  	return ret;
  }
0ec249146   Greg Kroah-Hartman   Drivers: ata: rem...
298
  static int pxa_ata_remove(struct platform_device *pdev)
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
299
  {
d89995db5   Jingoo Han   ata: use platform...
300
  	struct ata_host *host = platform_get_drvdata(pdev);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
301
  	struct pata_pxa_data *data = host->ports[0]->private_data;
88622d80a   Robert Jarzmik   ata: pata_pxa: dm...
302
  	dma_release_channel(data->dma_chan);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
303
304
305
306
307
308
309
310
  
  	ata_host_detach(host);
  
  	return 0;
  }
  
  static struct platform_driver pxa_ata_driver = {
  	.probe		= pxa_ata_probe,
0ec249146   Greg Kroah-Hartman   Drivers: ata: rem...
311
  	.remove		= pxa_ata_remove,
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
312
313
  	.driver		= {
  		.name		= DRV_NAME,
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
314
315
  	},
  };
99c8ea3e5   Axel Lin   SATA/PATA: conver...
316
  module_platform_driver(pxa_ata_driver);
2dc6c6f15   Marek Vasut   [ARM] pata_pxa: D...
317
318
319
320
321
322
  
  MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
  MODULE_DESCRIPTION("DMA-capable driver for PATA on PXA CPU");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  MODULE_ALIAS("platform:" DRV_NAME);