aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/lib/delay.c
blob: 5995969e8c42b4c4b0d6a1f44005104429c50479 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
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
/*
 * 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.
 *
 * Copyright (C) 1994 by Waldorf Electronics
 * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle
 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
 * Copyright (C) 2007  Maciej W. Rozycki
 */
#include <linux/module.h>
#include <linux/param.h>
#include <linux/smp.h>

#include <asm/compiler.h>
#include <asm/war.h>

inline void __delay(unsigned int loops)
{
	__asm__ __volatile__ (
	"	.set	noreorder				\n"
	"	.align	3					\n"
	"1:	bnez	%0, 1b					\n"
	"	subu	%0, 1					\n"
	"	.set	reorder					\n"
	: "=r" (loops)
	: "0" (loops));
}
EXPORT_SYMBOL(__delay);

/*
 * Division by multiplication: you don't have to worry about
 * loss of precision.
 *
 * Use only for very small delays ( < 1 msec).  Should probably use a
 * lookup table, really, as the multiplications take much too long with
 * short delays.  This is a "reasonable" implementation, though (and the
 * first constant multiplications gets optimized away if the delay is
 * a constant)
 */

void __udelay(unsigned long us)
{
	unsigned int lpj = raw_current_cpu_data.udelay_val;

	__delay((us * 0x000010c7ull * HZ * lpj) >> 32);
}
EXPORT_SYMBOL(__udelay);

void __ndelay(unsigned long ns)
{
	unsigned int lpj = raw_current_cpu_data.udelay_val;

	__delay((ns * 0x00000005ull * HZ * lpj) >> 32);
}
EXPORT_SYMBOL(__ndelay);
19:28:25 -0500 committer Ralf Baechle <ralf@linux-mips.org> 2007-02-09 11:23:15 -0500 [TC] MIPS: TURBOchannel update to the driver model' href='/cgit/cgit.cgi/litmus-rt-budgetable-locks.git/.git/commit/drivers/tc/tc.c?h=update_litmus_2019&id=b454cc6636d254fbf6049b73e9560aee76fb04a3'>b454cc6636d2
1da177e4c3f4
a5fc9c0bbee8
b454cc6636d2
1da177e4c3f4
b454cc6636d2



a5fc9c0bbee8
1da177e4c3f4
b454cc6636d2
1da177e4c3f4

b454cc6636d2





1da177e4c3f4


b454cc6636d2
1da177e4c3f4

b454cc6636d2









1da177e4c3f4


b454cc6636d2








a5fc9c0bbee8
df388556d7d8
b454cc6636d2



1da177e4c3f4
a5fc9c0bbee8
b454cc6636d2





1da177e4c3f4
b454cc6636d2



df388556d7d8
b454cc6636d2












df388556d7d8
b454cc6636d2


1da177e4c3f4
b454cc6636d2



a5fc9c0bbee8
b454cc6636d2



a5fc9c0bbee8
1da177e4c3f4



b454cc6636d2
1da177e4c3f4
778220f7c4a3
1da177e4c3f4
b454cc6636d2

778220f7c4a3
1da177e4c3f4
b454cc6636d2
df388556d7d8
b454cc6636d2












56a47da1b940
b454cc6636d2










56a47da1b940
b454cc6636d2








a5fc9c0bbee8
b454cc6636d2

1da177e4c3f4
778220f7c4a3

1da177e4c3f4


1
2
3
4
5
6
7
8
9
10
11
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
158
159
160
161
162
163
164
165
166
167
168
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
  
                                  
  


                                                               
  


                                                                   
   

                           
                       
                         
                         
                       
                         
                       
                         
                     
                        
 
                   
 


                               
 
  
                                    
   
                                                          
 






                                                              
                         
                      
                    
 



                                                                       
                                
 
                                    

                        





                                                                             


                                                               
                                            

                                









                                                                        


                                                               








                                                                            
                 
                                                       



                                              
 
                                         





                                                                             
                 



                                      
                                                                             












                                                                           
                                                                   


                                                                 
                 



                                                      
 



                                                           
                                



         
                  
   
                               
 

                                             
                         
 
                                        
                                        












                                                                        
                                                                










                                                                         
                                                                        








                                                                        
                 

                                            
         

                 


                         
/*
 *	TURBOchannel bus services.
 *
 *	Copyright (c) Harald Koerfgen, 1998
 *	Copyright (c) 2001, 2003, 2005, 2006  Maciej W. Rozycki
 *	Copyright (c) 2005  James Simmons
 *
 *	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.
 */
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tc.h>
#include <linux/types.h>

#include <asm/io.h>

static struct tc_bus tc_bus = {
	.name = "TURBOchannel",
};

/*
 * Probing for TURBOchannel modules.
 */
static void __init tc_bus_add_devices(struct tc_bus *tbus)
{
	resource_size_t slotsize = tbus->info.slot_size << 20;
	resource_size_t extslotsize = tbus->ext_slot_size;
	resource_size_t slotaddr;
	resource_size_t extslotaddr;
	resource_size_t devsize;
	void __iomem *module;
	struct tc_dev *tdev;
	int i, slot, err;
	u8 pattern[4];
	long offset;

	for (slot = 0; slot < tbus->num_tcslots; slot++) {
		slotaddr = tbus->slot_base + slot * slotsize;
		extslotaddr = tbus->ext_slot_base + slot * extslotsize;
		module = ioremap_nocache(slotaddr, slotsize);
		BUG_ON(!module);

		offset = TC_OLDCARD;

		err = 0;
		err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
		err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
		err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
		err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
		if (err)
			goto out_err;

		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
		    pattern[2] != 0xaa || pattern[3] != 0xff) {
			offset = TC_NEWCARD;

			err = 0;
			err |= tc_preadb(pattern + 0,
					 module + offset + TC_PATTERN0);
			err |= tc_preadb(pattern + 1,
					 module + offset + TC_PATTERN1);
			err |= tc_preadb(pattern + 2,
					 module + offset + TC_PATTERN2);
			err |= tc_preadb(pattern + 3,
					 module + offset + TC_PATTERN3);
			if (err)
				goto out_err;
		}

		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
		    pattern[2] != 0xaa || pattern[3] != 0xff)
			goto out_err;

		/* Found a board, allocate it an entry in the list */
		tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
		if (!tdev) {
			printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
			       slot);
			goto out_err;
		}
		dev_set_name(&tdev->dev, "tc%x", slot);
		tdev->bus = tbus;
		tdev->dev.parent = &tbus->dev;
		tdev->dev.bus = &tc_bus_type;
		tdev->slot = slot;

		for (i = 0; i < 8; i++) {
			tdev->firmware[i] =
				readb(module + offset + TC_FIRM_VER + 4 * i);
			tdev->vendor[i] =
				readb(module + offset + TC_VENDOR + 4 * i);
			tdev->name[i] =
				readb(module + offset + TC_MODULE + 4 * i);
		}
		tdev->firmware[8] = 0;
		tdev->vendor[8] = 0;
		tdev->name[8] = 0;

		pr_info("%s: %s %s %s\n", dev_name(&tdev->dev), tdev->vendor,
			tdev->name, tdev->firmware);

		devsize = readb(module + offset + TC_SLOT_SIZE);
		devsize <<= 22;
		if (devsize <= slotsize) {
			tdev->resource.start = slotaddr;
			tdev->resource.end = slotaddr + devsize - 1;
		} else if (devsize <= extslotsize) {
			tdev->resource.start = extslotaddr;
			tdev->resource.end = extslotaddr + devsize - 1;
		} else {
			printk(KERN_ERR "%s: Cannot provide slot space "
			       "(%dMiB required, up to %dMiB supported)\n",
			       dev_name(&tdev->dev), devsize >> 20,
			       max(slotsize, extslotsize) >> 20);
			kfree(tdev);
			goto out_err;
		}
		tdev->resource.name = tdev->name;
		tdev->resource.flags = IORESOURCE_MEM;

		tc_device_get_irq(tdev);

		device_register(&tdev->dev);
		list_add_tail(&tdev->node, &tbus->devices);

out_err:
		iounmap(module);
	}
}

/*
 * The main entry.
 */
static int __init tc_init(void)
{
	/* Initialize the TURBOchannel bus */
	if (tc_bus_get_info(&tc_bus))
		return 0;

	INIT_LIST_HEAD(&tc_bus.devices);
	dev_set_name(&tc_bus.dev, "tc");
	device_register(&tc_bus.dev);

	if (tc_bus.info.slot_size) {
		unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;

		pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
			"(with%s parity)\n", tc_bus.info.revision,
			tc_clock / 10, tc_clock % 10,
			tc_bus.info.parity ? "" : "out");

		tc_bus.resource[0].start = tc_bus.slot_base;
		tc_bus.resource[0].end = tc_bus.slot_base +
					 (tc_bus.info.slot_size << 20) *
					 tc_bus.num_tcslots - 1;
		tc_bus.resource[0].name = tc_bus.name;
		tc_bus.resource[0].flags = IORESOURCE_MEM;
		if (request_resource(&iomem_resource,
				     &tc_bus.resource[0]) < 0) {
			printk(KERN_ERR "tc: Cannot reserve resource\n");
			return 0;
		}
		if (tc_bus.ext_slot_size) {
			tc_bus.resource[1].start = tc_bus.ext_slot_base;
			tc_bus.resource[1].end = tc_bus.ext_slot_base +
						 tc_bus.ext_slot_size *
						 tc_bus.num_tcslots - 1;
			tc_bus.resource[1].name = tc_bus.name;
			tc_bus.resource[1].flags = IORESOURCE_MEM;
			if (request_resource(&iomem_resource,
					     &tc_bus.resource[1]) < 0) {
				printk(KERN_ERR
				       "tc: Cannot reserve resource\n");
				release_resource(&tc_bus.resource[0]);
				return 0;
			}
		}

		tc_bus_add_devices(&tc_bus);
	}

	return 0;
}

subsys_initcall(tc_init);