1/* $Id: parport.h,v 1.1.1.1 2007/08/03 18:53:36 Exp $
2 * parport.h: sparc64 specific parport initialization and dma.
3 *
4 * Copyright (C) 1999  Eddie C. Dost  (ecd@skynet.be)
5 */
6
7#ifndef _ASM_SPARC64_PARPORT_H
8#define _ASM_SPARC64_PARPORT_H 1
9
10#include <asm/ebus.h>
11#include <asm/isa.h>
12#include <asm/ns87303.h>
13
14#define PARPORT_PC_MAX_PORTS	PARPORT_MAX
15
16/*
17 * While sparc64 doesn't have an ISA DMA API, we provide something that looks
18 * close enough to make parport_pc happy
19 */
20#define HAS_DMA
21
22static DEFINE_SPINLOCK(dma_spin_lock);
23
24#define claim_dma_lock() \
25({	unsigned long flags; \
26	spin_lock_irqsave(&dma_spin_lock, flags); \
27	flags; \
28})
29
30#define release_dma_lock(__flags) \
31	spin_unlock_irqrestore(&dma_spin_lock, __flags);
32
33static struct sparc_ebus_info {
34	struct ebus_dma_info info;
35	unsigned int addr;
36	unsigned int count;
37	int lock;
38} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
39
40static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
41{
42	if (dmanr >= PARPORT_PC_MAX_PORTS)
43		return -EINVAL;
44	if (xchg(&sparc_ebus_dmas[dmanr].lock, 1) != 0)
45		return -EBUSY;
46	return 0;
47}
48
49static __inline__ void free_dma(unsigned int dmanr)
50{
51	if (dmanr >= PARPORT_PC_MAX_PORTS) {
52		printk(KERN_WARNING "Trying to free DMA%d\n", dmanr);
53		return;
54	}
55	if (xchg(&sparc_ebus_dmas[dmanr].lock, 0) == 0) {
56		printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr);
57		return;
58	}
59}
60
61static __inline__ void enable_dma(unsigned int dmanr)
62{
63	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
64
65	if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info,
66			     sparc_ebus_dmas[dmanr].addr,
67			     sparc_ebus_dmas[dmanr].count))
68		BUG();
69}
70
71static __inline__ void disable_dma(unsigned int dmanr)
72{
73	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0);
74}
75
76static __inline__ void clear_dma_ff(unsigned int dmanr)
77{
78	/* nothing */
79}
80
81static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
82{
83	ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE));
84}
85
86static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int addr)
87{
88	sparc_ebus_dmas[dmanr].addr = addr;
89}
90
91static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
92{
93	sparc_ebus_dmas[dmanr].count = count;
94}
95
96static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
97{
98	return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
99}
100
101static int ebus_ecpp_p(struct linux_ebus_device *edev)
102{
103	if (!strcmp(edev->prom_node->name, "ecpp"))
104		return 1;
105	if (!strcmp(edev->prom_node->name, "parallel")) {
106		const char *compat;
107
108		compat = of_get_property(edev->prom_node,
109					 "compatible", NULL);
110		if (compat &&
111		    (!strcmp(compat, "ecpp") ||
112		     !strcmp(compat, "ns87317-ecpp") ||
113		     !strcmp(compat + 13, "ecpp")))
114			return 1;
115	}
116	return 0;
117}
118
119static int parport_isa_probe(int count)
120{
121	struct sparc_isa_bridge *isa_br;
122	struct sparc_isa_device *isa_dev;
123
124	for_each_isa(isa_br) {
125		for_each_isadev(isa_dev, isa_br) {
126			struct sparc_isa_device *child;
127			unsigned long base;
128
129			if (strcmp(isa_dev->prom_node->name, "dma"))
130				continue;
131
132			child = isa_dev->child;
133			while (child) {
134				if (!strcmp(child->prom_node->name, "parallel"))
135					break;
136				child = child->next;
137			}
138			if (!child)
139				continue;
140
141			base = child->resource.start;
142
143			/* No DMA, see commentary in
144			 * asm-sparc64/floppy.h:isa_floppy_init()
145			 */
146			if (parport_pc_probe_port(base, base + 0x400,
147						  child->irq, PARPORT_DMA_NOFIFO,
148						  &child->bus->self->dev))
149				count++;
150		}
151	}
152
153	return count;
154}
155
156static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
157{
158	struct linux_ebus *ebus;
159	struct linux_ebus_device *edev;
160	int count = 0;
161
162	for_each_ebus(ebus) {
163		for_each_ebusdev(edev, ebus) {
164			if (ebus_ecpp_p(edev)) {
165				unsigned long base = edev->resource[0].start;
166				unsigned long config = edev->resource[1].start;
167				unsigned long d_base = edev->resource[2].start;
168				unsigned long d_len;
169
170				spin_lock_init(&sparc_ebus_dmas[count].info.lock);
171				d_len = (edev->resource[2].end -
172					 d_base) + 1;
173				sparc_ebus_dmas[count].info.regs =
174					ioremap(d_base, d_len);
175				if (!sparc_ebus_dmas[count].info.regs)
176					continue;
177				sparc_ebus_dmas[count].info.flags = 0;
178				sparc_ebus_dmas[count].info.callback = NULL;
179				sparc_ebus_dmas[count].info.client_cookie = NULL;
180				sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
181				strcpy(sparc_ebus_dmas[count].info.name, "parport");
182				if (ebus_dma_register(&sparc_ebus_dmas[count].info))
183					continue;
184				ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
185
186				/* Configure IRQ to Push Pull, Level Low */
187				/* Enable ECP, set bit 2 of the CTR first */
188				outb(0x04, base + 0x02);
189				ns87303_modify(config, PCR,
190					       PCR_EPP_ENABLE |
191					       PCR_IRQ_ODRAIN,
192					       PCR_ECP_ENABLE |
193					       PCR_ECP_CLK_ENA |
194					       PCR_IRQ_POLAR);
195
196				/* CTR bit 5 controls direction of port */
197				ns87303_modify(config, PTR,
198					       0, PTR_LPT_REG_DIR);
199
200				if (parport_pc_probe_port(base, base + 0x400,
201							  edev->irqs[0],
202							  count,
203							  &ebus->self->dev))
204					count++;
205			}
206		}
207	}
208
209	count = parport_isa_probe(count);
210
211	return count;
212}
213
214#endif /* !(_ASM_SPARC64_PARPORT_H */
215