ide-h8300.c 5.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * H8/300 generic IDE interface
 */

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

#include <asm/io.h>
#include <asm/irq.h>

11 12
#define DRV_NAME "ide-h8300"

L
Linus Torvalds 已提交
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
#define bswap(d) \
({					\
	u16 r;				\
	__asm__("mov.b %w1,r1h\n\t"	\
		"mov.b %x1,r1l\n\t"	\
		"mov.w r1,%0"		\
		:"=r"(r)		\
		:"r"(d)			\
		:"er1");		\
	(r);				\
})

static void mm_outw(u16 d, unsigned long a)
{
	__asm__("mov.b %w0,r2h\n\t"
		"mov.b %x0,r2l\n\t"
		"mov.w r2,@%1"
		:
		:"r"(d),"r"(a)
		:"er2");
}

static u16 mm_inw(unsigned long a)
{
	register u16 r __asm__("er0");
	__asm__("mov.w @%1,r2\n\t"
		"mov.b r2l,%x0\n\t"
		"mov.b r2h,%w0"
		:"=r"(r)
		:"r"(a)
		:"er2");
	return r;
}

47
static void h8300_tf_load(ide_drive_t *drive, struct ide_cmd *cmd)
48 49 50
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
51 52
	struct ide_taskfile *tf = &cmd->tf;
	u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
53

54
	if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
55 56
		HIHI = 0xFF;

57
	if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA)
58 59
		mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr);

60
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
61
		outb(tf->hob_feature, io_ports->feature_addr);
62
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
63
		outb(tf->hob_nsect, io_ports->nsect_addr);
64
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
65
		outb(tf->hob_lbal, io_ports->lbal_addr);
66
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
67
		outb(tf->hob_lbam, io_ports->lbam_addr);
68
	if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
69 70
		outb(tf->hob_lbah, io_ports->lbah_addr);

71
	if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE)
72
		outb(tf->feature, io_ports->feature_addr);
73
	if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT)
74
		outb(tf->nsect, io_ports->nsect_addr);
75
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL)
76
		outb(tf->lbal, io_ports->lbal_addr);
77
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM)
78
		outb(tf->lbam, io_ports->lbam_addr);
79
	if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH)
80 81
		outb(tf->lbah, io_ports->lbah_addr);

82
	if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE)
83
		outb((tf->device & HIHI) | drive->select,
84 85 86
		     io_ports->device_addr);
}

87
static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd)
88 89 90
{
	ide_hwif_t *hwif = drive->hwif;
	struct ide_io_ports *io_ports = &hwif->io_ports;
91
	struct ide_taskfile *tf = &cmd->tf;
92

93
	if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
94 95 96 97 98 99 100
		u16 data = mm_inw(io_ports->data_addr);

		tf->data = data & 0xff;
		tf->hob_data = (data >> 8) & 0xff;
	}

	/* be sure we're looking at the low order bits */
101
	outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
102

103
	if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE)
104
		tf->feature = inb(io_ports->feature_addr);
105
	if (cmd->tf_flags & IDE_TFLAG_IN_NSECT)
106
		tf->nsect  = inb(io_ports->nsect_addr);
107
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAL)
108
		tf->lbal   = inb(io_ports->lbal_addr);
109
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAM)
110
		tf->lbam   = inb(io_ports->lbam_addr);
111
	if (cmd->tf_flags & IDE_TFLAG_IN_LBAH)
112
		tf->lbah   = inb(io_ports->lbah_addr);
113
	if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE)
114 115
		tf->device = inb(io_ports->device_addr);

116
	if (cmd->tf_flags & IDE_TFLAG_LBA48) {
117
		outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
118

119
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
120
			tf->hob_feature = inb(io_ports->feature_addr);
121
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
122
			tf->hob_nsect   = inb(io_ports->nsect_addr);
123
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
124
			tf->hob_lbal    = inb(io_ports->lbal_addr);
125
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
126
			tf->hob_lbam    = inb(io_ports->lbam_addr);
127
		if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
128 129 130 131
			tf->hob_lbah    = inb(io_ports->lbah_addr);
	}
}

L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145
static void mm_outsw(unsigned long addr, void *buf, u32 len)
{
	unsigned short *bp = (unsigned short *)buf;
	for (; len > 0; len--, bp++)
		*(volatile u16 *)addr = bswap(*bp);
}

static void mm_insw(unsigned long addr, void *buf, u32 len)
{
	unsigned short *bp = (unsigned short *)buf;
	for (; len > 0; len--, bp++)
		*bp = bswap(*(volatile u16 *)addr);
}

146
static void h8300_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
147 148 149 150 151
			     void *buf, unsigned int len)
{
	mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
}

152
static void h8300_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
153 154 155 156 157
			      void *buf, unsigned int len)
{
	mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171
static const struct ide_tp_ops h8300_tp_ops = {
	.exec_command		= ide_exec_command,
	.read_status		= ide_read_status,
	.read_altstatus		= ide_read_altstatus,

	.set_irq		= ide_set_irq,

	.tf_load		= h8300_tf_load,
	.tf_read		= h8300_tf_read,

	.input_data		= h8300_input_data,
	.output_data		= h8300_output_data,
};

L
Linus Torvalds 已提交
172 173 174 175 176 177 178
#define H8300_IDE_GAP (2)

static inline void hw_setup(hw_regs_t *hw)
{
	int i;

	memset(hw, 0, sizeof(hw_regs_t));
179 180 181
	for (i = 0; i <= 7; i++)
		hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
	hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
L
Linus Torvalds 已提交
182 183 184 185
	hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
	hw->chipset = ide_generic;
}

186
static const struct ide_port_info h8300_port_info = {
187
	.tp_ops			= &h8300_tp_ops,
188 189 190
	.host_flags		= IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA,
};

191
static int __init h8300_ide_init(void)
L
Linus Torvalds 已提交
192
{
193
	hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
L
Linus Torvalds 已提交
194

195 196
	printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n");

L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205
	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
		goto out_busy;
	if (!request_region(CONFIG_H8300_IDE_ALT, H8300_IDE_GAP, "ide-h8300")) {
		release_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8);
		goto out_busy;
	}

	hw_setup(&hw);

206
	return ide_host_add(&h8300_port_info, hws, NULL);
L
Linus Torvalds 已提交
207 208 209

out_busy:
	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
210 211

	return -EBUSY;
L
Linus Torvalds 已提交
212
}
213 214

module_init(h8300_ide_init);
215 216

MODULE_LICENSE("GPL");