Blame view

arch/sparc/kernel/central.c 5.95 KB
d979f1792   David S. Miller   [SPARC64]: __inli...
1
  /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
b69416b51   David S. Miller   sparc64: Rewrite ...
3
   * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
   */
  
  #include <linux/kernel.h>
  #include <linux/types.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
8
  #include <linux/slab.h>
7b64db608   Paul Gortmaker   sparc: add export...
9
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/init.h>
b69416b51   David S. Miller   sparc64: Rewrite ...
12
13
  #include <linux/of_device.h>
  #include <linux/platform_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <asm/fhc.h>
b69416b51   David S. Miller   sparc64: Rewrite ...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include <asm/upa.h>
  
  struct clock_board {
  	void __iomem		*clock_freq_regs;
  	void __iomem		*clock_regs;
  	void __iomem		*clock_ver_reg;
  	int			num_slots;
  	struct resource		leds_resource;
  	struct platform_device	leds_pdev;
  };
  
  struct fhc {
  	void __iomem		*pregs;
  	bool			central;
  	bool			jtag_master;
  	int			board_num;
  	struct resource		leds_resource;
  	struct platform_device	leds_pdev;
  };
7c9503b83   Greg Kroah-Hartman   SPARC: drivers: r...
35
  static int clock_board_calc_nslots(struct clock_board *p)
b69416b51   David S. Miller   sparc64: Rewrite ...
36
37
  {
  	u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

b69416b51   David S. Miller   sparc64: Rewrite ...
39
40
41
  	switch (reg) {
  	case 0x40:
  		return 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

b69416b51   David S. Miller   sparc64: Rewrite ...
43
44
  	case 0xc0:
  		return 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

b69416b51   David S. Miller   sparc64: Rewrite ...
46
47
48
49
50
51
52
53
54
55
56
57
58
  	case 0x80:
  		reg = 0;
  		if (p->clock_ver_reg)
  			reg = upa_readb(p->clock_ver_reg);
  		if (reg) {
  			if (reg & 0x80)
  				return 4;
  			else
  				return 5;
  		}
  		/* Fallthrough */
  	default:
  		return 4;
cecc4e922   David S. Miller   [SPARC64]: Conver...
59
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  }
7c9503b83   Greg Kroah-Hartman   SPARC: drivers: r...
61
  static int clock_board_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  {
b69416b51   David S. Miller   sparc64: Rewrite ...
63
64
  	struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
  	int err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

b69416b51   David S. Miller   sparc64: Rewrite ...
66
67
68
69
  	if (!p) {
  		printk(KERN_ERR "clock_board: Cannot allocate struct clock_board
  ");
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

b69416b51   David S. Miller   sparc64: Rewrite ...
72
73
74
75
76
77
78
79
  	p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
  					resource_size(&op->resource[0]),
  					"clock_board_freq");
  	if (!p->clock_freq_regs) {
  		printk(KERN_ERR "clock_board: Cannot map clock_freq_regs
  ");
  		goto out_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

b69416b51   David S. Miller   sparc64: Rewrite ...
81
82
83
84
85
86
87
88
  	p->clock_regs = of_ioremap(&op->resource[1], 0,
  				   resource_size(&op->resource[1]),
  				   "clock_board_regs");
  	if (!p->clock_regs) {
  		printk(KERN_ERR "clock_board: Cannot map clock_regs
  ");
  		goto out_unmap_clock_freq_regs;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

b69416b51   David S. Miller   sparc64: Rewrite ...
90
91
92
93
94
95
96
97
98
99
  	if (op->resource[2].flags) {
  		p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
  					      resource_size(&op->resource[2]),
  					      "clock_ver_reg");
  		if (!p->clock_ver_reg) {
  			printk(KERN_ERR "clock_board: Cannot map clock_ver_reg
  ");
  			goto out_unmap_clock_regs;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

b69416b51   David S. Miller   sparc64: Rewrite ...
101
  	p->num_slots = clock_board_calc_nslots(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102

b69416b51   David S. Miller   sparc64: Rewrite ...
103
104
  	p->leds_resource.start = (unsigned long)
  		(p->clock_regs + CLOCK_CTRL);
093171465   Roel Kluin   sparc: leds_resou...
105
  	p->leds_resource.end = p->leds_resource.start;
b69416b51   David S. Miller   sparc64: Rewrite ...
106
  	p->leds_resource.name = "leds";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

b69416b51   David S. Miller   sparc64: Rewrite ...
108
  	p->leds_pdev.name = "sunfire-clockboard-leds";
b7c18c1b2   David S. Miller   sparc64: Initiali...
109
  	p->leds_pdev.id = -1;
b69416b51   David S. Miller   sparc64: Rewrite ...
110
111
112
  	p->leds_pdev.resource = &p->leds_resource;
  	p->leds_pdev.num_resources = 1;
  	p->leds_pdev.dev.parent = &op->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

b69416b51   David S. Miller   sparc64: Rewrite ...
114
115
116
117
118
119
  	err = platform_device_register(&p->leds_pdev);
  	if (err) {
  		printk(KERN_ERR "clock_board: Could not register LEDS "
  		       "platform device
  ");
  		goto out_unmap_clock_ver_reg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121

b69416b51   David S. Miller   sparc64: Rewrite ...
122
123
124
  	printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.
  ",
  	       p->num_slots);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

b69416b51   David S. Miller   sparc64: Rewrite ...
126
127
128
  	err = 0;
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

b69416b51   David S. Miller   sparc64: Rewrite ...
130
131
132
133
  out_unmap_clock_ver_reg:
  	if (p->clock_ver_reg)
  		of_iounmap(&op->resource[2], p->clock_ver_reg,
  			   resource_size(&op->resource[2]));
cecc4e922   David S. Miller   [SPARC64]: Conver...
134

b69416b51   David S. Miller   sparc64: Rewrite ...
135
136
137
  out_unmap_clock_regs:
  	of_iounmap(&op->resource[1], p->clock_regs,
  		   resource_size(&op->resource[1]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

b69416b51   David S. Miller   sparc64: Rewrite ...
139
140
141
  out_unmap_clock_freq_regs:
  	of_iounmap(&op->resource[0], p->clock_freq_regs,
  		   resource_size(&op->resource[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

b69416b51   David S. Miller   sparc64: Rewrite ...
143
144
145
  out_free:
  	kfree(p);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  }
3628aa065   David S. Miller   sparc64: Fix sect...
147
  static const struct of_device_id clock_board_match[] = {
b69416b51   David S. Miller   sparc64: Rewrite ...
148
149
150
151
152
  	{
  		.name = "clock-board",
  	},
  	{},
  };
4ebb24f70   Grant Likely   dt/sparc: Elimina...
153
  static struct platform_driver clock_board_driver = {
b69416b51   David S. Miller   sparc64: Rewrite ...
154
  	.probe		= clock_board_probe,
4018294b5   Grant Likely   of: Remove duplic...
155
156
  	.driver = {
  		.name = "clock_board",
4018294b5   Grant Likely   of: Remove duplic...
157
  		.of_match_table = clock_board_match,
b69416b51   David S. Miller   sparc64: Rewrite ...
158
159
  	},
  };
7c9503b83   Greg Kroah-Hartman   SPARC: drivers: r...
160
  static int fhc_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
b69416b51   David S. Miller   sparc64: Rewrite ...
162
163
164
  	struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
  	int err = -ENOMEM;
  	u32 reg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165

b69416b51   David S. Miller   sparc64: Rewrite ...
166
167
168
169
  	if (!p) {
  		printk(KERN_ERR "fhc: Cannot allocate struct fhc
  ");
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  	}
61c7a080a   Grant Likely   of: Always use 's...
171
  	if (!strcmp(op->dev.of_node->parent->name, "central"))
b69416b51   David S. Miller   sparc64: Rewrite ...
172
  		p->central = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173

b69416b51   David S. Miller   sparc64: Rewrite ...
174
175
176
177
178
179
180
  	p->pregs = of_ioremap(&op->resource[0], 0,
  			      resource_size(&op->resource[0]),
  			      "fhc_pregs");
  	if (!p->pregs) {
  		printk(KERN_ERR "fhc: Cannot map pregs
  ");
  		goto out_free;
cecc4e922   David S. Miller   [SPARC64]: Conver...
181
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

b69416b51   David S. Miller   sparc64: Rewrite ...
183
184
185
186
  	if (p->central) {
  		reg = upa_readl(p->pregs + FHC_PREGS_BSR);
  		p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
  	} else {
61c7a080a   Grant Likely   of: Always use 's...
187
  		p->board_num = of_getintprop_default(op->dev.of_node, "board#", -1);
b69416b51   David S. Miller   sparc64: Rewrite ...
188
189
190
191
192
193
194
195
  		if (p->board_num == -1) {
  			printk(KERN_ERR "fhc: No board# property
  ");
  			goto out_unmap_pregs;
  		}
  		if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
  			p->jtag_master = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

b69416b51   David S. Miller   sparc64: Rewrite ...
197
198
199
  	if (!p->central) {
  		p->leds_resource.start = (unsigned long)
  			(p->pregs + FHC_PREGS_CTRL);
093171465   Roel Kluin   sparc: leds_resou...
200
  		p->leds_resource.end = p->leds_resource.start;
b69416b51   David S. Miller   sparc64: Rewrite ...
201
202
203
  		p->leds_resource.name = "leds";
  
  		p->leds_pdev.name = "sunfire-fhc-leds";
b7c18c1b2   David S. Miller   sparc64: Initiali...
204
  		p->leds_pdev.id = p->board_num;
b69416b51   David S. Miller   sparc64: Rewrite ...
205
206
207
208
209
210
211
212
213
214
215
216
217
  		p->leds_pdev.resource = &p->leds_resource;
  		p->leds_pdev.num_resources = 1;
  		p->leds_pdev.dev.parent = &op->dev;
  
  		err = platform_device_register(&p->leds_pdev);
  		if (err) {
  			printk(KERN_ERR "fhc: Could not register LEDS "
  			       "platform device
  ");
  			goto out_unmap_pregs;
  		}
  	}
  	reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218

b69416b51   David S. Miller   sparc64: Rewrite ...
219
220
  	if (!p->central)
  		reg |= FHC_CONTROL_IXIST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

b69416b51   David S. Miller   sparc64: Rewrite ...
222
223
224
  	reg &= ~(FHC_CONTROL_AOFF |
  		 FHC_CONTROL_BOFF |
  		 FHC_CONTROL_SLINE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

b69416b51   David S. Miller   sparc64: Rewrite ...
226
227
  	upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
  	upa_readl(p->pregs + FHC_PREGS_CTRL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

b69416b51   David S. Miller   sparc64: Rewrite ...
229
230
231
232
233
234
235
236
237
238
  	reg = upa_readl(p->pregs + FHC_PREGS_ID);
  	printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s
  ",
  	       p->board_num,
  	       (reg & FHC_ID_VERS) >> 28,
  	       (reg & FHC_ID_PARTID) >> 12,
  	       (reg & FHC_ID_MANUF) >> 1,
  	       (p->jtag_master ?
  		"(JTAG Master)" :
  		(p->central ? "(Central)" : "")));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

b69416b51   David S. Miller   sparc64: Rewrite ...
240
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

b69416b51   David S. Miller   sparc64: Rewrite ...
242
243
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244

b69416b51   David S. Miller   sparc64: Rewrite ...
245
246
  out_unmap_pregs:
  	of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

b69416b51   David S. Miller   sparc64: Rewrite ...
248
249
250
  out_free:
  	kfree(p);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  }
3628aa065   David S. Miller   sparc64: Fix sect...
252
  static const struct of_device_id fhc_match[] = {
b69416b51   David S. Miller   sparc64: Rewrite ...
253
254
255
256
257
  	{
  		.name = "fhc",
  	},
  	{},
  };
4ebb24f70   Grant Likely   dt/sparc: Elimina...
258
  static struct platform_driver fhc_driver = {
b69416b51   David S. Miller   sparc64: Rewrite ...
259
  	.probe		= fhc_probe,
4018294b5   Grant Likely   of: Remove duplic...
260
261
  	.driver = {
  		.name = "fhc",
4018294b5   Grant Likely   of: Remove duplic...
262
  		.of_match_table = fhc_match,
b69416b51   David S. Miller   sparc64: Rewrite ...
263
264
265
266
  	},
  };
  
  static int __init sunfire_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  {
4ebb24f70   Grant Likely   dt/sparc: Elimina...
268
269
  	(void) platform_driver_register(&fhc_driver);
  	(void) platform_driver_register(&clock_board_driver);
b69416b51   David S. Miller   sparc64: Rewrite ...
270
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  }
b69416b51   David S. Miller   sparc64: Rewrite ...
272

a5a737e09   David S. Miller   sparc64: Do not c...
273
  fs_initcall(sunfire_init);