3 Copyright (C) 2004-2012 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <exec/types.h>
24 #include <expansion/pci.h>
26 #include <proto/exec.h>
27 #include <proto/expansion.h>
33 #include "pci_protos.h"
34 #include "expansion_protos.h"
35 #include "timer_protos.h"
38 /* Private prototypes */
40 static VOID
WordsInIOHook(struct BusContext
*context
, ULONG offset
,
41 UWORD
*buffer
, ULONG count
);
42 static VOID
WordsOutIOHook(struct BusContext
*context
, ULONG offset
,
43 const UWORD
*buffer
, ULONG count
);
44 static VOID
BEWordOutIOHook(struct BusContext
*context
, ULONG offset
,
46 static UWORD
LEWordInIOHook(struct BusContext
*context
, ULONG offset
);
47 static VOID
LEWordOutIOHook(struct BusContext
*context
, ULONG offset
,
51 IMPORT
const UWORD product_codes
[];
54 static const struct TagItem bridge_unit_tags
[] =
56 {IOTAG_WordsIn
, (UPINT
)WordsInIOHook
},
57 {IOTAG_WordsOut
, (UPINT
)WordsOutIOHook
},
58 {IOTAG_BEWordOut
, (UPINT
)BEWordOutIOHook
},
59 {IOTAG_LEWordIn
, (UPINT
)LEWordInIOHook
},
60 {IOTAG_LEWordOut
, (UPINT
)LEWordOutIOHook
},
65 /****i* prism2.device/GetExpansionCount ************************************
68 * GetExpansionCount -- Get the number of compatible PCI Cards.
71 * count = GetExpansionCount()
73 * ULONG GetExpansionCount();
75 ****************************************************************************
79 ULONG
GetExpansionCount(struct DevBase
*base
)
82 struct PCIDevice
*card
;
84 if(base
->i_pci
!= NULL
)
87 base
->i_pci
->FindDeviceTags(FDT_CandidateList
, product_codes
,
88 FDT_Index
, count
, TAG_END
)) != NULL
)
90 base
->i_pci
->FreeDevice(card
);
100 /****i* prism2.device/AllocExpansionCard ***********************************
106 * context = AllocExpansionCard(index)
108 * struct BusContext *AllocExpansionCard(ULONG);
110 ****************************************************************************
114 struct BusContext
*AllocExpansionCard(ULONG index
, struct DevBase
*base
)
117 struct BusContext
*context
;
118 struct PCIDevice
*card
= NULL
;
119 struct PCIResourceRange
*io_range
= NULL
;
123 volatile UBYTE
*cor_reg
;
125 /* Find a compatible card */
127 context
= AllocMem(sizeof(struct BusContext
), MEMF_PUBLIC
| MEMF_CLEAR
);
133 context
->card
= card
=
134 base
->i_pci
->FindDeviceTags(FDT_CandidateList
, product_codes
,
135 FDT_Index
, index
, TAG_END
);
143 success
= card
->Lock(PCI_LOCK_EXCLUSIVE
);
147 /* Find out what type of Prism II PCI card this is */
149 card
->SetEndian(PCI_MODE_BIG_ENDIAN
);
150 context
->bus_type
= GetBusType(card
->ReadConfigWord(PCI_DEVICE_ID
),
153 if(context
->bus_type
== TMD_BUS
)
155 /* Reset and enable the PCCard */
157 io_range
= card
->GetResourceRange(1);
158 card
->OutByte(io_range
->BaseAddress
, COR_RESET
);
159 BusyMilliDelay(RESET_DELAY
, base
);
160 card
->OutByte(io_range
->BaseAddress
, COR_ENABLE
);
161 BusyMilliDelay(RESET_DELAY
, base
);
162 card
->FreeResourceRange(io_range
);
164 context
->unit_tags
= bridge_unit_tags
;
166 else if(context
->bus_type
== PLX_BUS
)
168 /* Reset and enable the PCCard */
170 io_range
= card
->GetResourceRange(2);
171 cor_reg
= (volatile UBYTE
*)io_range
->BaseAddress
+ 0x3e0;
172 *cor_reg
= COR_ENABLE
;
173 BusyMilliDelay(RESET_DELAY
, base
);
174 card
->FreeResourceRange(io_range
);
176 /* Enable interrupts on the bridge */
178 io_range
= card
->GetResourceRange(1);
179 int_reg
= io_range
->BaseAddress
+ PLX9052_INTS
;
180 card
->FreeResourceRange(io_range
);
181 value
= card
->InLong(int_reg
);
182 card
->OutLong(int_reg
, value
| (1 << 6));
183 if((card
->InLong(int_reg
) & (1 << 6)) == 0)
186 context
->unit_tags
= bridge_unit_tags
;
190 card
->WriteConfigWord(PCI_COMMAND
, PCI_COMMAND_MEMORY
);
195 /* Get the I/O base of the wireless chip */
197 context
->have_card
= TRUE
;
198 card
->SetEndian(PCI_MODE_LITTLE_ENDIAN
);
199 io_range
= card
->GetResourceRange(io_range_no
);
200 context
->io_base
= io_range
->BaseAddress
;
201 card
->FreeResourceRange(io_range
);
203 if(context
->bus_type
== PCI_BUS
)
205 /* Reset and enable the card */
207 cor_reg
= (volatile UBYTE
*)context
->io_base
+ (P2_REG_PCICOR
* 2);
208 *cor_reg
= COR_RESET
;
209 BusyMilliDelay(250, base
);
211 BusyMilliDelay(500, base
);
217 FreeExpansionCard(context
, base
);
226 /****i* prism2.device/FreeExpansionCard ************************************
232 * FreeExpansionCard(context)
234 * VOID FreeExpansionCard(struct BusContext *);
236 ****************************************************************************
240 VOID
FreeExpansionCard(struct BusContext
*context
, struct DevBase
*base
)
242 struct PCIDevice
*card
;
243 struct PCIResourceRange
*io_range
= NULL
;
246 volatile UBYTE
*cor_reg
;
250 card
= context
->card
;
253 if(context
->bus_type
== TMD_BUS
)
255 /* Disable the PCCard */
257 io_range
= card
->GetResourceRange(1);
258 card
->OutByte(io_range
->BaseAddress
, 0);
259 card
->FreeResourceRange(io_range
);
261 else if(context
->bus_type
== PLX_BUS
)
263 /* Disable interrupts on the bridge */
265 io_range
= card
->GetResourceRange(1);
266 int_reg
= io_range
->BaseAddress
+ PLX9052_INTS
;
267 card
->FreeResourceRange(io_range
);
268 value
= card
->InLong(int_reg
);
269 card
->OutLong(int_reg
, value
& ~(1 << 6));
271 /* Disable the PCCard */
273 io_range
= card
->GetResourceRange(2);
274 cor_reg
= (volatile UBYTE
*)io_range
->BaseAddress
+ 0x3e0;
275 *cor_reg
= COR_RESET
;
276 BusyMilliDelay(250, base
);
279 card
->FreeResourceRange(io_range
);
282 if(context
->have_card
)
284 base
->i_pci
->FreeDevice(card
);
285 FreeMem(context
, sizeof(struct BusContext
));
294 /****i* prism2.device/AddExpansionIntServer ********************************
297 * AddExpansionIntServer
300 * success = AddExpansionIntServer(card, interrupt)
302 * BOOL AddExpansionIntServer(APTR, struct Interrupt *);
304 ****************************************************************************
308 BOOL
AddExpansionIntServer(APTR card
, struct Interrupt
*interrupt
,
309 struct DevBase
*base
)
311 return AddIntServer(((struct PCIDevice
*)card
)->MapInterrupt(),
317 /****i* prism2.device/RemExpansionIntServer ********************************
320 * RemExpansionIntServer
323 * RemExpansionIntServer(card, interrupt)
325 * VOID RemExpansionIntServer(APTR, struct Interrupt *);
327 ****************************************************************************
331 VOID
RemExpansionIntServer(APTR card
, struct Interrupt
*interrupt
,
332 struct DevBase
*base
)
334 RemIntServer(((struct PCIDevice
*)card
)->MapInterrupt(), interrupt
);
341 /****i* prism2.device/WordsInIOHook ****************************************
347 * WordsInIOHook(context, offset, buffer, count)
349 * VOID WordsInIOHook(struct BusContext *, ULONG, UWORD *, ULONG);
351 ****************************************************************************
355 static VOID
WordsInIOHook(struct BusContext
*context
, ULONG offset
,
356 UWORD
*buffer
, ULONG count
)
358 struct PCIDevice
*card
;
360 card
= context
->card
;
362 *buffer
++ = card
->InWord(context
->io_base
+ offset
);
369 /****i* prism2.device/WordsOutIOHook ***************************************
375 * WordsOutIOHook(context, offset, buffer,
378 * VOID WordsOutIOHook(struct BusContext *, ULONG, const UWORD *,
381 ****************************************************************************
385 static VOID
WordsOutIOHook(struct BusContext
*context
, ULONG offset
,
386 const UWORD
*buffer
, ULONG count
)
388 struct PCIDevice
*card
;
390 card
= context
->card
;
392 card
->OutWord(context
->io_base
+ offset
, *buffer
++);
399 /****i* prism2.device/BEWordOutIOHook **************************************
405 * BEWordOutIOHook(context, offset, value)
407 * VOID BEWordOutIOHook(struct BusContext *, ULONG, UWORD);
409 ****************************************************************************
413 static VOID
BEWordOutIOHook(struct BusContext
*context
, ULONG offset
,
416 struct PCIDevice
*card
;
418 card
= context
->card
;
419 card
->OutWord(context
->io_base
+ offset
, MakeBEWord(value
));
426 /****i* prism2.device/LEWordInIOHook ***************************************
432 * value = LEWordInIOHook(context, offset)
434 * UWORD LEWordInIOHook(struct BusContext *, ULONG);
436 ****************************************************************************
440 static UWORD
LEWordInIOHook(struct BusContext
*context
, ULONG offset
)
442 struct PCIDevice
*card
;
444 card
= context
->card
;
445 return LEWord(card
->InWord(context
->io_base
+ offset
));
450 /****i* prism2.device/LEWordOutIOHook **************************************
456 * LEWordOutIOHook(context, offset, value)
458 * VOID LEWordOutIOHook(struct BusContext *, ULONG, UWORD);
460 ****************************************************************************
464 static VOID
LEWordOutIOHook(struct BusContext
*context
, ULONG offset
,
467 struct PCIDevice
*card
;
469 card
= context
->card
;
470 card
->OutWord(context
->io_base
+ offset
, MakeLEWord(value
));