ide-io-std.c 7.9 KB
Newer Older
1 2 3 4

#include <linux/kernel.h>
#include <linux/ide.h>

5 6 7 8 9 10 11
#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
    defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
#include <asm/ide.h>
#else
#include <asm-generic/ide_iops.h>
#endif

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/*
 *	Conventional PIO operations for ATA devices
 */

static u8 ide_inb(unsigned long port)
{
	return (u8) inb(port);
}

static void ide_outb(u8 val, unsigned long port)
{
	outb(val, port);
}

/*
 *	MMIO operations, typically used for SATA controllers
 */

static u8 ide_mm_inb(unsigned long port)
{
	return (u8) readb((void __iomem *) port);
}

static void ide_mm_outb(u8 value, unsigned long port)
{
	writeb(value, (void __iomem *) port);
}

void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
{
	if (hwif->host_flags & IDE_HFLAG_MMIO)
		writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
	else
		outb(cmd, hwif->io_ports.command_addr);
}
EXPORT_SYMBOL_GPL(ide_exec_command);

u8 ide_read_status(ide_hwif_t *hwif)
{
	if (hwif->host_flags & IDE_HFLAG_MMIO)
		return readb((void __iomem *)hwif->io_ports.status_addr);
	else
		return inb(hwif->io_ports.status_addr);
}
EXPORT_SYMBOL_GPL(ide_read_status);

u8 ide_read_altstatus(ide_hwif_t *hwif)
{
	if (hwif->host_flags & IDE_HFLAG_MMIO)
		return readb((void __iomem *)hwif->io_ports.ctl_addr);
	else
		return inb(hwif->io_ports.ctl_addr);
}
EXPORT_SYMBOL_GPL(ide_read_altstatus);

67
void ide_write_devctl(ide_hwif_t *hwif, u8 ctl)
68 69 70 71 72 73
{
	if (hwif->host_flags & IDE_HFLAG_MMIO)
		writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
	else
		outb(ctl, hwif->io_ports.ctl_addr);
}
74
EXPORT_SYMBOL_GPL(ide_write_devctl);
75

76 77 78 79 80 81 82 83 84 85 86 87
void ide_dev_select(ide_drive_t *drive)
{
	ide_hwif_t *hwif = drive->hwif;
	u8 select = drive->select | ATA_DEVICE_OBS;

	if (hwif->host_flags & IDE_HFLAG_MMIO)
		writeb(select, (void __iomem *)hwif->io_ports.device_addr);
	else
		outb(select, hwif->io_ports.device_addr);
}
EXPORT_SYMBOL_GPL(ide_dev_select);

88
void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
89 90 91
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
92
	struct ide_taskfile *tf = &cmd->tf;
93 94
	void (*tf_outb)(u8 addr, unsigned long port);
	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
95
	u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
96 97 98 99 100 101

	if (mmio)
		tf_outb = ide_mm_outb;
	else
		tf_outb = ide_outb;

102
	if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
103 104
		HIHI = 0xFF;

105
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
106
		tf_outb(tf->hob_feature, io_ports->feature_addr);
107
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
108
		tf_outb(tf->hob_nsect, io_ports->nsect_addr);
109
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
110
		tf_outb(tf->hob_lbal, io_ports->lbal_addr);
111
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
112
		tf_outb(tf->hob_lbam, io_ports->lbam_addr);
113
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
114 115
		tf_outb(tf->hob_lbah, io_ports->lbah_addr);

116
	if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
117
		tf_outb(tf->feature, io_ports->feature_addr);
118
	if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
119
		tf_outb(tf->nsect, io_ports->nsect_addr);
120
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
121
		tf_outb(tf->lbal, io_ports->lbal_addr);
122
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
123
		tf_outb(tf->lbam, io_ports->lbam_addr);
124
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
125 126
		tf_outb(tf->lbah, io_ports->lbah_addr);

127
	if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
128 129 130 131 132
		tf_outb((tf->device & HIHI) | drive->select,
			 io_ports->device_addr);
}
EXPORT_SYMBOL_GPL(ide_tf_load);

133
void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
134 135 136
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
137
	struct ide_taskfile *tf = &cmd->tf;
138 139 140 141 142 143 144 145 146 147 148 149 150
	void (*tf_outb)(u8 addr, unsigned long port);
	u8 (*tf_inb)(unsigned long port);
	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;

	if (mmio) {
		tf_outb = ide_mm_outb;
		tf_inb  = ide_mm_inb;
	} else {
		tf_outb = ide_outb;
		tf_inb  = ide_inb;
	}

	/* be sure we're looking at the low order bits */
S
Sergei Shtylyov 已提交
151
	tf_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr);
152

153 154
	if (cmd->tf_flags & IDE_TFLAG_IN_ERROR)
		tf->error  = tf_inb(io_ports->feature_addr);
155
	if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
156
		tf->nsect  = tf_inb(io_ports->nsect_addr);
157
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
158
		tf->lbal   = tf_inb(io_ports->lbal_addr);
159
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
160
		tf->lbam   = tf_inb(io_ports->lbam_addr);
161
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
162
		tf->lbah   = tf_inb(io_ports->lbah_addr);
163
	if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
164 165
		tf->device = tf_inb(io_ports->device_addr);

166
	if (cmd->tf_flags & IDE_TFLAG_LBA48) {
S
Sergei Shtylyov 已提交
167
		tf_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr);
168

169 170
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR)
			tf->hob_error = tf_inb(io_ports->feature_addr);
171
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
172
			tf->hob_nsect = tf_inb(io_ports->nsect_addr);
173
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
174
			tf->hob_lbal  = tf_inb(io_ports->lbal_addr);
175
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
176
			tf->hob_lbam  = tf_inb(io_ports->lbam_addr);
177
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
178
			tf->hob_lbah  = tf_inb(io_ports->lbah_addr);
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
	}
}
EXPORT_SYMBOL_GPL(ide_tf_read);

/*
 * Some localbus EIDE interfaces require a special access sequence
 * when using 32-bit I/O instructions to transfer data.  We call this
 * the "vlb_sync" sequence, which consists of three successive reads
 * of the sector count register location, with interrupts disabled
 * to ensure that the reads all happen together.
 */
static void ata_vlb_sync(unsigned long port)
{
	(void)inb(port);
	(void)inb(port);
	(void)inb(port);
}

/*
 * This is used for most PIO data transfers *from* the IDE interface
 *
 * These routines will round up any request for an odd number of bytes,
 * so if an odd len is specified, be sure that there's at least one
 * extra byte allocated for the buffer.
 */
204
void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
205 206 207 208 209
		    unsigned int len)
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
	unsigned long data_addr = io_ports->data_addr;
210
	unsigned int words = (len + 1) >> 1;
211 212 213 214 215 216 217 218 219 220 221
	u8 io_32bit = drive->io_32bit;
	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;

	if (io_32bit) {
		unsigned long uninitialized_var(flags);

		if ((io_32bit & 2) && !mmio) {
			local_irq_save(flags);
			ata_vlb_sync(io_ports->nsect_addr);
		}

222
		words >>= 1;
223
		if (mmio)
224
			__ide_mm_insl((void __iomem *)data_addr, buf, words);
225
		else
226
			insl(data_addr, buf, words);
227 228 229 230

		if ((io_32bit & 2) && !mmio)
			local_irq_restore(flags);

231 232 233 234 235
		if (((len + 1) & 3) < 2)
			return;

		buf += len & ~3;
		words = 1;
236
	}
237 238 239 240 241

	if (mmio)
		__ide_mm_insw((void __iomem *)data_addr, buf, words);
	else
		insw(data_addr, buf, words);
242 243 244 245 246 247
}
EXPORT_SYMBOL_GPL(ide_input_data);

/*
 * This is used for most PIO data transfers *to* the IDE interface
 */
248
void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
249 250 251 252 253
		     unsigned int len)
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
	unsigned long data_addr = io_ports->data_addr;
254
	unsigned int words = (len + 1) >> 1;
255 256 257 258 259 260 261 262 263 264 265
	u8 io_32bit = drive->io_32bit;
	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;

	if (io_32bit) {
		unsigned long uninitialized_var(flags);

		if ((io_32bit & 2) && !mmio) {
			local_irq_save(flags);
			ata_vlb_sync(io_ports->nsect_addr);
		}

266
		words >>= 1;
267
		if (mmio)
268
			__ide_mm_outsl((void __iomem *)data_addr, buf, words);
269
		else
270
			outsl(data_addr, buf, words);
271 272 273 274

		if ((io_32bit & 2) && !mmio)
			local_irq_restore(flags);

275 276 277 278 279
		if (((len + 1) & 3) < 2)
			return;

		buf += len & ~3;
		words = 1;
280
	}
281 282 283 284 285

	if (mmio)
		__ide_mm_outsw((void __iomem *)data_addr, buf, words);
	else
		outsw(data_addr, buf, words);
286 287 288 289 290 291 292
}
EXPORT_SYMBOL_GPL(ide_output_data);

const struct ide_tp_ops default_tp_ops = {
	.exec_command		= ide_exec_command,
	.read_status		= ide_read_status,
	.read_altstatus		= ide_read_altstatus,
293
	.write_devctl		= ide_write_devctl,
294

295
	.dev_select		= ide_dev_select,
296 297 298 299 300 301
	.tf_load		= ide_tf_load,
	.tf_read		= ide_tf_read,

	.input_data		= ide_input_data,
	.output_data		= ide_output_data,
};