Blame view

drivers/ssb/driver_mipscore.c 8.78 KB
61e115a56   Michael Buesch   [SSB]: add Sonics...
1
2
3
4
5
  /*
   * Sonics Silicon Backplane
   * Broadcom MIPS core driver
   *
   * Copyright 2005, Broadcom Corporation
eb032b983   Michael Buesch   Update my e-mail ...
6
   * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
61e115a56   Michael Buesch   [SSB]: add Sonics...
7
8
9
   *
   * Licensed under the GNU/GPL. See COPYING for details.
   */
b8b6069cf   Michael Buesch   ssb: Remove home-...
10
  #include "ssb_private.h"
61e115a56   Michael Buesch   [SSB]: add Sonics...
11
  #include <linux/ssb/ssb.h>
c7a4a9e38   Rafał Miłecki   ssb: register pla...
12
  #include <linux/mtd/physmap.h>
61e115a56   Michael Buesch   [SSB]: add Sonics...
13
14
15
16
  #include <linux/serial.h>
  #include <linux/serial_core.h>
  #include <linux/serial_reg.h>
  #include <linux/time.h>
21400f252   Rafał Miłecki   MIPS: BCM47XX: Ma...
17
  #ifdef CONFIG_BCM47XX
138173d4e   Rafał Miłecki   MIPS: BCM47xx: Mo...
18
  #include <linux/bcm47xx_nvram.h>
21400f252   Rafał Miłecki   MIPS: BCM47XX: Ma...
19
  #endif
61e115a56   Michael Buesch   [SSB]: add Sonics...
20

255e9fd4b   Artem Bityutskiy   ssb: driver_mipsc...
21
  static const char * const part_probes[] = { "bcm47xxpart", NULL };
c7a4a9e38   Rafał Miłecki   ssb: register pla...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  
  static struct physmap_flash_data ssb_pflash_data = {
  	.part_probe_types	= part_probes,
  };
  
  static struct resource ssb_pflash_resource = {
  	.name	= "ssb_pflash",
  	.flags  = IORESOURCE_MEM,
  };
  
  struct platform_device ssb_pflash_dev = {
  	.name		= "physmap-flash",
  	.dev		= {
  		.platform_data  = &ssb_pflash_data,
  	},
  	.resource	= &ssb_pflash_resource,
  	.num_resources	= 1,
  };
61e115a56   Michael Buesch   [SSB]: add Sonics...
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
  
  static inline u32 mips_read32(struct ssb_mipscore *mcore,
  			      u16 offset)
  {
  	return ssb_read32(mcore->dev, offset);
  }
  
  static inline void mips_write32(struct ssb_mipscore *mcore,
  				u16 offset,
  				u32 value)
  {
  	ssb_write32(mcore->dev, offset, value);
  }
  
  static const u32 ipsflag_irq_mask[] = {
  	0,
  	SSB_IPSFLAG_IRQ1,
  	SSB_IPSFLAG_IRQ2,
  	SSB_IPSFLAG_IRQ3,
  	SSB_IPSFLAG_IRQ4,
  };
  
  static const u32 ipsflag_irq_shift[] = {
  	0,
  	SSB_IPSFLAG_IRQ1_SHIFT,
  	SSB_IPSFLAG_IRQ2_SHIFT,
  	SSB_IPSFLAG_IRQ3_SHIFT,
  	SSB_IPSFLAG_IRQ4_SHIFT,
  };
  
  static inline u32 ssb_irqflag(struct ssb_device *dev)
  {
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
  	if (tpsflag)
  		return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
  	else
  		/* not irq supported */
  		return 0x3f;
  }
  
  static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
  {
  	struct ssb_bus *bus = rdev->bus;
  	int i;
  	for (i = 0; i < bus->nr_devices; i++) {
  		struct ssb_device *dev;
  		dev = &(bus->devices[i]);
  		if (ssb_irqflag(dev) == irqflag)
  			return dev;
  	}
  	return NULL;
61e115a56   Michael Buesch   [SSB]: add Sonics...
91
92
93
94
  }
  
  /* Get the MIPS IRQ assignment for a specified device.
   * If unassigned, 0 is returned.
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
95
96
   * If disabled, 5 is returned.
   * If not supported, 6 is returned.
61e115a56   Michael Buesch   [SSB]: add Sonics...
97
98
99
100
   */
  unsigned int ssb_mips_irq(struct ssb_device *dev)
  {
  	struct ssb_bus *bus = dev->bus;
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
101
  	struct ssb_device *mdev = bus->mipscore.dev;
61e115a56   Michael Buesch   [SSB]: add Sonics...
102
103
104
105
106
107
  	u32 irqflag;
  	u32 ipsflag;
  	u32 tmp;
  	unsigned int irq;
  
  	irqflag = ssb_irqflag(dev);
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
108
109
  	if (irqflag == 0x3f)
  		return 6;
61e115a56   Michael Buesch   [SSB]: add Sonics...
110
111
112
113
114
115
  	ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
  	for (irq = 1; irq <= 4; irq++) {
  		tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
  		if (tmp == irqflag)
  			break;
  	}
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
116
117
118
119
  	if (irq	== 5) {
  		if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
  			irq = 0;
  	}
61e115a56   Michael Buesch   [SSB]: add Sonics...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  
  	return irq;
  }
  
  static void clear_irq(struct ssb_bus *bus, unsigned int irq)
  {
  	struct ssb_device *dev = bus->mipscore.dev;
  
  	/* Clear the IRQ in the MIPScore backplane registers */
  	if (irq == 0) {
  		ssb_write32(dev, SSB_INTVEC, 0);
  	} else {
  		ssb_write32(dev, SSB_IPSFLAG,
  			    ssb_read32(dev, SSB_IPSFLAG) |
  			    ipsflag_irq_mask[irq]);
  	}
  }
  
  static void set_irq(struct ssb_device *dev, unsigned int irq)
  {
  	unsigned int oldirq = ssb_mips_irq(dev);
  	struct ssb_bus *bus = dev->bus;
  	struct ssb_device *mdev = bus->mipscore.dev;
  	u32 irqflag = ssb_irqflag(dev);
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
144
  	BUG_ON(oldirq == 6);
61e115a56   Michael Buesch   [SSB]: add Sonics...
145
  	dev->irq = irq + 2;
61e115a56   Michael Buesch   [SSB]: add Sonics...
146
147
148
  	/* clear the old irq */
  	if (oldirq == 0)
  		ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
149
  	else if (oldirq != 5)
61e115a56   Michael Buesch   [SSB]: add Sonics...
150
151
152
  		clear_irq(bus, oldirq);
  
  	/* assign the new one */
2633da237   Michael Buesch   ssb-mipscore: Fix...
153
154
155
  	if (irq == 0) {
  		ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
  	} else {
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
156
157
158
159
160
161
162
  		u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
  		if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
  			u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
  			struct ssb_device *olddev = find_device(dev, oldipsflag);
  			if (olddev)
  				set_irq(olddev, 0);
  		}
2633da237   Michael Buesch   ssb-mipscore: Fix...
163
  		irqflag <<= ipsflag_irq_shift[irq];
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
164
  		irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
2633da237   Michael Buesch   ssb-mipscore: Fix...
165
166
  		ssb_write32(mdev, SSB_IPSFLAG, irqflag);
  	}
b8b6069cf   Michael Buesch   ssb: Remove home-...
167
168
  	dev_dbg(dev->dev, "set_irq: core 0x%04x, irq %d => %d
  ",
33a606ac8   Joe Perches   ssb: Convert ssb_...
169
  		dev->id.coreid, oldirq+2, irq+2);
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
170
171
172
173
  }
  
  static void print_irq(struct ssb_device *dev, unsigned int irq)
  {
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
174
  	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
b8b6069cf   Michael Buesch   ssb: Remove home-...
175
176
177
  	dev_dbg(dev->dev,
  		"core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s
  ",
33a606ac8   Joe Perches   ssb: Convert ssb_...
178
179
180
181
182
183
184
185
  		dev->id.coreid,
  		irq_name[0], irq == 0 ? "*" : " ",
  		irq_name[1], irq == 1 ? "*" : " ",
  		irq_name[2], irq == 2 ? "*" : " ",
  		irq_name[3], irq == 3 ? "*" : " ",
  		irq_name[4], irq == 4 ? "*" : " ",
  		irq_name[5], irq == 5 ? "*" : " ",
  		irq_name[6], irq == 6 ? "*" : " ");
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
186
187
188
189
190
191
192
193
194
195
  }
  
  static void dump_irq(struct ssb_bus *bus)
  {
  	int i;
  	for (i = 0; i < bus->nr_devices; i++) {
  		struct ssb_device *dev;
  		dev = &(bus->devices[i]);
  		print_irq(dev, ssb_mips_irq(dev));
  	}
61e115a56   Michael Buesch   [SSB]: add Sonics...
196
197
198
199
200
  }
  
  static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
  {
  	struct ssb_bus *bus = mcore->dev->bus;
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
201
  	if (ssb_extif_available(&bus->extif))
61e115a56   Michael Buesch   [SSB]: add Sonics...
202
  		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
203
  	else if (ssb_chipco_available(&bus->chipco))
61e115a56   Michael Buesch   [SSB]: add Sonics...
204
205
206
207
208
209
210
211
  		mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
  	else
  		mcore->nr_serial_ports = 0;
  }
  
  static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
  {
  	struct ssb_bus *bus = mcore->dev->bus;
21400f252   Rafał Miłecki   MIPS: BCM47XX: Ma...
212
  	struct ssb_sflash *sflash = &mcore->sflash;
f1ab57e3a   Rafał Miłecki   ssb: trivial: use...
213
  	struct ssb_pflash *pflash = &mcore->pflash;
61e115a56   Michael Buesch   [SSB]: add Sonics...
214

902d9e0f4   Rafał Miłecki   ssb: check for fl...
215
  	/* When there is no chipcommon on the bus there is 4MB flash */
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
216
  	if (!ssb_chipco_available(&bus->chipco)) {
f1ab57e3a   Rafał Miłecki   ssb: trivial: use...
217
218
219
220
  		pflash->present = true;
  		pflash->buswidth = 2;
  		pflash->window = SSB_FLASH1;
  		pflash->window_size = SSB_FLASH1_SZ;
c7a4a9e38   Rafał Miłecki   ssb: register pla...
221
  		goto ssb_pflash;
902d9e0f4   Rafał Miłecki   ssb: check for fl...
222
223
224
225
226
227
  	}
  
  	/* There is ChipCommon, so use it to read info about flash */
  	switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
  	case SSB_CHIPCO_FLASHT_STSER:
  	case SSB_CHIPCO_FLASHT_ATSER:
b8b6069cf   Michael Buesch   ssb: Remove home-...
228
229
  		dev_dbg(mcore->dev->dev, "Found serial flash
  ");
72a525cbb   Rafał Miłecki   ssb: add place fo...
230
  		ssb_sflash_init(&bus->chipco);
902d9e0f4   Rafał Miłecki   ssb: check for fl...
231
232
  		break;
  	case SSB_CHIPCO_FLASHT_PARA:
b8b6069cf   Michael Buesch   ssb: Remove home-...
233
234
  		dev_dbg(mcore->dev->dev, "Found parallel flash
  ");
f1ab57e3a   Rafał Miłecki   ssb: trivial: use...
235
236
237
  		pflash->present = true;
  		pflash->window = SSB_FLASH2;
  		pflash->window_size = SSB_FLASH2_SZ;
61e115a56   Michael Buesch   [SSB]: add Sonics...
238
239
  		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
  		               & SSB_CHIPCO_CFG_DS16) == 0)
f1ab57e3a   Rafał Miłecki   ssb: trivial: use...
240
  			pflash->buswidth = 1;
902d9e0f4   Rafał Miłecki   ssb: check for fl...
241
  		else
f1ab57e3a   Rafał Miłecki   ssb: trivial: use...
242
  			pflash->buswidth = 2;
902d9e0f4   Rafał Miłecki   ssb: check for fl...
243
  		break;
61e115a56   Michael Buesch   [SSB]: add Sonics...
244
  	}
c7a4a9e38   Rafał Miłecki   ssb: register pla...
245
246
  
  ssb_pflash:
21400f252   Rafał Miłecki   MIPS: BCM47XX: Ma...
247
248
249
250
251
252
253
254
  	if (sflash->present) {
  #ifdef CONFIG_BCM47XX
  		bcm47xx_nvram_init_from_mem(sflash->window, sflash->size);
  #endif
  	} else if (pflash->present) {
  #ifdef CONFIG_BCM47XX
  		bcm47xx_nvram_init_from_mem(pflash->window, pflash->window_size);
  #endif
c7a4a9e38   Rafał Miłecki   ssb: register pla...
255
256
257
258
  		ssb_pflash_data.width = pflash->buswidth;
  		ssb_pflash_resource.start = pflash->window;
  		ssb_pflash_resource.end = pflash->window + pflash->window_size;
  	}
61e115a56   Michael Buesch   [SSB]: add Sonics...
259
260
261
262
263
264
  }
  
  u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
  {
  	struct ssb_bus *bus = mcore->dev->bus;
  	u32 pll_type, n, m, rate = 0;
d486a5b49   Hauke Mehrtens   ssb: add support ...
265
266
  	if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
  		return ssb_pmu_get_cpu_clock(&bus->chipco);
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
267
  	if (ssb_extif_available(&bus->extif)) {
61e115a56   Michael Buesch   [SSB]: add Sonics...
268
  		ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
269
  	} else if (ssb_chipco_available(&bus->chipco)) {
61e115a56   Michael Buesch   [SSB]: add Sonics...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  		ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
  	} else
  		return 0;
  
  	if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
  		rate = 200000000;
  	} else {
  		rate = ssb_calc_clock_rate(pll_type, n, m);
  	}
  
  	if (pll_type == SSB_PLLTYPE_6) {
  		rate *= 2;
  	}
  
  	return rate;
  }
  
  void ssb_mipscore_init(struct ssb_mipscore *mcore)
  {
7007d00ca   Felix Fietkau   [PATCH] ssb: Fix ...
289
  	struct ssb_bus *bus;
61e115a56   Michael Buesch   [SSB]: add Sonics...
290
291
292
293
294
295
  	struct ssb_device *dev;
  	unsigned long hz, ns;
  	unsigned int irq, i;
  
  	if (!mcore->dev)
  		return; /* We don't have a MIPS core */
b8b6069cf   Michael Buesch   ssb: Remove home-...
296
297
  	dev_dbg(mcore->dev->dev, "Initializing MIPS core...
  ");
61e115a56   Michael Buesch   [SSB]: add Sonics...
298

7007d00ca   Felix Fietkau   [PATCH] ssb: Fix ...
299
  	bus = mcore->dev->bus;
61e115a56   Michael Buesch   [SSB]: add Sonics...
300
301
302
303
  	hz = ssb_clockspeed(bus);
  	if (!hz)
  		hz = 100000000;
  	ns = 1000000000 / hz;
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
304
  	if (ssb_extif_available(&bus->extif))
61e115a56   Michael Buesch   [SSB]: add Sonics...
305
  		ssb_extif_timing_init(&bus->extif, ns);
0362063b7   Hauke Mehrtens   ssb: extif: fix c...
306
  	else if (ssb_chipco_available(&bus->chipco))
61e115a56   Michael Buesch   [SSB]: add Sonics...
307
308
309
310
  		ssb_chipco_timing_init(&bus->chipco, ns);
  
  	/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
  	for (irq = 2, i = 0; i < bus->nr_devices; i++) {
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
311
  		int mips_irq;
61e115a56   Michael Buesch   [SSB]: add Sonics...
312
  		dev = &(bus->devices[i]);
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
313
314
315
316
317
318
319
  		mips_irq = ssb_mips_irq(dev);
  		if (mips_irq > 4)
  			dev->irq = 0;
  		else
  			dev->irq = mips_irq + 2;
  		if (dev->irq > 5)
  			continue;
61e115a56   Michael Buesch   [SSB]: add Sonics...
320
321
322
323
324
325
  		switch (dev->id.coreid) {
  		case SSB_DEV_USB11_HOST:
  			/* shouldn't need a separate irq line for non-4710, most of them have a proper
  			 * external usb controller on the pci */
  			if ((bus->chip_id == 0x4710) && (irq <= 4)) {
  				set_irq(dev, irq++);
61e115a56   Michael Buesch   [SSB]: add Sonics...
326
  			}
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
327
  			break;
61e115a56   Michael Buesch   [SSB]: add Sonics...
328
329
  		case SSB_DEV_PCI:
  		case SSB_DEV_ETHERNET:
aab547ce0   Michael Buesch   ssb: Add Gigabit ...
330
  		case SSB_DEV_ETHERNET_GBIT:
61e115a56   Michael Buesch   [SSB]: add Sonics...
331
332
333
334
335
336
337
  		case SSB_DEV_80211:
  		case SSB_DEV_USB20_HOST:
  			/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
  			if (irq <= 4) {
  				set_irq(dev, irq++);
  				break;
  			}
83e34f03e   Jochen Friedrich   ssb: fix interrup...
338
339
340
341
  			/* fallthrough */
  		case SSB_DEV_EXTIF:
  			set_irq(dev, 0);
  			break;
61e115a56   Michael Buesch   [SSB]: add Sonics...
342
343
  		}
  	}
b8b6069cf   Michael Buesch   ssb: Remove home-...
344
345
  	dev_dbg(mcore->dev->dev, "after irq reconfiguration
  ");
ea4bbfd00   Matthieu CASTET   MIPS: BC47xx: Fix...
346
  	dump_irq(bus);
61e115a56   Michael Buesch   [SSB]: add Sonics...
347
348
349
350
  
  	ssb_mips_serial_init(mcore);
  	ssb_mips_flash_detect(mcore);
  }