2 * arch/ppc/platforms/mpc8260_pci9.c
4 * Workaround for device erratum PCI 9.
5 * See Motorola's "XPC826xA Family Device Errata Reference."
6 * The erratum applies to all 8260 family Hip4 processors. It is scheduled
7 * to be fixed in HiP4 Rev C. Erratum PCI 9 states that a simultaneous PCI
8 * inbound write transaction and PCI outbound read transaction can result in a
9 * bus deadlock. The suggested workaround is to use the IDMA controller to
10 * perform all reads from PCI configuration, memory, and I/O space.
12 * Author: andy_lowe@mvista.com
14 * 2003 (c) MontaVista Software, Inc. This file is licensed under
15 * the terms of the GNU General Public License version 2. This program
16 * is licensed "as is" without any warranty of any kind, whether express
19 #include <linux/kernel.h>
20 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/pci.h>
23 #include <linux/types.h>
24 #include <linux/string.h>
27 #include <asm/pci-bridge.h>
28 #include <asm/machdep.h>
29 #include <asm/byteorder.h>
30 #include <asm/mpc8260.h>
31 #include <asm/immap_cpm2.h>
34 #include "m8260_pci.h"
36 #ifdef CONFIG_8260_PCI9
37 /*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
39 #define IDMA_XFER_BUF_SIZE 64 /* size of the IDMA transfer buffer */
41 /* define a structure for the IDMA dpram usage */
42 typedef struct idma_dpram_s
{
43 idma_t pram
; /* IDMA parameter RAM */
44 u_char xfer_buf
[IDMA_XFER_BUF_SIZE
]; /* IDMA transfer buffer */
45 idma_bd_t bd
; /* buffer descriptor */
48 /* define offsets relative to start of IDMA dpram */
49 #define IDMA_XFER_BUF_OFFSET (sizeof(idma_t))
50 #define IDMA_BD_OFFSET (sizeof(idma_t) + IDMA_XFER_BUF_SIZE)
53 static volatile idma_dpram_t
*idma_dpram
;
55 /* Exactly one of CONFIG_8260_PCI9_IDMAn must be defined,
56 * where n is 1, 2, 3, or 4. This selects the IDMA channel used for
57 * the PCI9 workaround.
59 #ifdef CONFIG_8260_PCI9_IDMA1
61 #define PROFF_IDMA PROFF_IDMA1_BASE
62 #define IDMA_PAGE CPM_CR_IDMA1_PAGE
63 #define IDMA_SBLOCK CPM_CR_IDMA1_SBLOCK
65 #ifdef CONFIG_8260_PCI9_IDMA2
67 #define PROFF_IDMA PROFF_IDMA2_BASE
68 #define IDMA_PAGE CPM_CR_IDMA2_PAGE
69 #define IDMA_SBLOCK CPM_CR_IDMA2_SBLOCK
71 #ifdef CONFIG_8260_PCI9_IDMA3
73 #define PROFF_IDMA PROFF_IDMA3_BASE
74 #define IDMA_PAGE CPM_CR_IDMA3_PAGE
75 #define IDMA_SBLOCK CPM_CR_IDMA3_SBLOCK
77 #ifdef CONFIG_8260_PCI9_IDMA4
79 #define PROFF_IDMA PROFF_IDMA4_BASE
80 #define IDMA_PAGE CPM_CR_IDMA4_PAGE
81 #define IDMA_SBLOCK CPM_CR_IDMA4_SBLOCK
84 void idma_pci9_init(void)
87 volatile idma_t
*pram
;
88 volatile im_idma_t
*idma_reg
;
89 volatile cpm2_map_t
*immap
= cpm2_immr
;
91 /* allocate IDMA dpram */
92 dpram_offset
= cpm_dpalloc(sizeof(idma_dpram_t
), 64);
93 idma_dpram
= cpm_dpram_addr(dpram_offset
);
95 /* initialize the IDMA parameter RAM */
96 memset((void *)idma_dpram
, 0, sizeof(idma_dpram_t
));
97 pram
= &idma_dpram
->pram
;
98 pram
->ibase
= dpram_offset
+ IDMA_BD_OFFSET
;
99 pram
->dpr_buf
= dpram_offset
+ IDMA_XFER_BUF_OFFSET
;
103 /* initialize the IDMA_BASE pointer to the IDMA parameter RAM */
104 *((ushort
*) &immap
->im_dprambase
[PROFF_IDMA
]) = dpram_offset
;
106 /* initialize the IDMA registers */
107 idma_reg
= (volatile im_idma_t
*) &immap
->im_sdma
.sdma_idsr1
;
108 idma_reg
[IDMA_CHAN
].idmr
= 0; /* mask all IDMA interrupts */
109 idma_reg
[IDMA_CHAN
].idsr
= 0xff; /* clear all event flags */
111 printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
117 /* Use the IDMA controller to transfer data from I/O memory to local RAM.
118 * The src address must be a physical address suitable for use by the DMA
119 * controller with no translation. The dst address must be a kernel virtual
120 * address. The dst address is translated to a physical address via
122 * The sinc argument specifies whether or not the source address is incremented
123 * by the DMA controller. The source address is incremented if and only if sinc
124 * is non-zero. The destination address is always incremented since the
125 * destination is always host RAM.
128 idma_pci9_read(u8
*dst
, u8
*src
, int bytes
, int unit_size
, int sinc
)
131 volatile idma_t
*pram
= &idma_dpram
->pram
;
132 volatile idma_bd_t
*bd
= &idma_dpram
->bd
;
133 volatile cpm2_map_t
*immap
= cpm2_immr
;
135 local_irq_save(flags
);
137 /* initialize IDMA parameter RAM for this transfer */
139 pram
->dcm
= IDMA_DCM_DMA_WRAP_64
| IDMA_DCM_SINC
140 | IDMA_DCM_DINC
| IDMA_DCM_SD_MEM2MEM
;
142 pram
->dcm
= IDMA_DCM_DMA_WRAP_64
| IDMA_DCM_DINC
143 | IDMA_DCM_SD_MEM2MEM
;
144 pram
->ibdptr
= pram
->ibase
;
145 pram
->sts
= unit_size
;
148 /* initialize the buffer descriptor */
149 bd
->dst
= virt_to_phys(dst
);
150 bd
->src
= (uint
) src
;
152 bd
->flags
= IDMA_BD_V
| IDMA_BD_W
| IDMA_BD_I
| IDMA_BD_L
| IDMA_BD_DGBL
153 | IDMA_BD_DBO_BE
| IDMA_BD_SBO_BE
| IDMA_BD_SDTB
;
155 /* issue the START_IDMA command to the CP */
156 while (immap
->im_cpm
.cp_cpcr
& CPM_CR_FLG
);
157 immap
->im_cpm
.cp_cpcr
= mk_cr_cmd(IDMA_PAGE
, IDMA_SBLOCK
, 0,
158 CPM_CR_START_IDMA
) | CPM_CR_FLG
;
159 while (immap
->im_cpm
.cp_cpcr
& CPM_CR_FLG
);
161 /* wait for transfer to complete */
162 while(bd
->flags
& IDMA_BD_V
);
164 local_irq_restore(flags
);
169 /* Use the IDMA controller to transfer data from I/O memory to local RAM.
170 * The dst address must be a physical address suitable for use by the DMA
171 * controller with no translation. The src address must be a kernel virtual
172 * address. The src address is translated to a physical address via
174 * The dinc argument specifies whether or not the dest address is incremented
175 * by the DMA controller. The source address is incremented if and only if sinc
176 * is non-zero. The source address is always incremented since the
177 * source is always host RAM.
180 idma_pci9_write(u8
*dst
, u8
*src
, int bytes
, int unit_size
, int dinc
)
183 volatile idma_t
*pram
= &idma_dpram
->pram
;
184 volatile idma_bd_t
*bd
= &idma_dpram
->bd
;
185 volatile cpm2_map_t
*immap
= cpm2_immr
;
187 local_irq_save(flags
);
189 /* initialize IDMA parameter RAM for this transfer */
191 pram
->dcm
= IDMA_DCM_DMA_WRAP_64
| IDMA_DCM_SINC
192 | IDMA_DCM_DINC
| IDMA_DCM_SD_MEM2MEM
;
194 pram
->dcm
= IDMA_DCM_DMA_WRAP_64
| IDMA_DCM_SINC
195 | IDMA_DCM_SD_MEM2MEM
;
196 pram
->ibdptr
= pram
->ibase
;
197 pram
->sts
= unit_size
;
200 /* initialize the buffer descriptor */
201 bd
->dst
= (uint
) dst
;
202 bd
->src
= virt_to_phys(src
);
204 bd
->flags
= IDMA_BD_V
| IDMA_BD_W
| IDMA_BD_I
| IDMA_BD_L
| IDMA_BD_DGBL
205 | IDMA_BD_DBO_BE
| IDMA_BD_SBO_BE
| IDMA_BD_SDTB
;
207 /* issue the START_IDMA command to the CP */
208 while (immap
->im_cpm
.cp_cpcr
& CPM_CR_FLG
);
209 immap
->im_cpm
.cp_cpcr
= mk_cr_cmd(IDMA_PAGE
, IDMA_SBLOCK
, 0,
210 CPM_CR_START_IDMA
) | CPM_CR_FLG
;
211 while (immap
->im_cpm
.cp_cpcr
& CPM_CR_FLG
);
213 /* wait for transfer to complete */
214 while(bd
->flags
& IDMA_BD_V
);
216 local_irq_restore(flags
);
221 /* Same as idma_pci9_read, but 16-bit little-endian byte swapping is performed
222 * if the unit_size is 2, and 32-bit little-endian byte swapping is performed if
223 * the unit_size is 4.
226 idma_pci9_read_le(u8
*dst
, u8
*src
, int bytes
, int unit_size
, int sinc
)
231 idma_pci9_read(dst
, src
, bytes
, unit_size
, sinc
);
234 for (i
= 0, p
= dst
; i
< bytes
; i
+= 2, p
+= 2)
238 for (i
= 0, p
= dst
; i
< bytes
; i
+= 4, p
+= 4)
245 EXPORT_SYMBOL(idma_pci9_init
);
246 EXPORT_SYMBOL(idma_pci9_read
);
247 EXPORT_SYMBOL(idma_pci9_read_le
);
249 static inline int is_pci_mem(unsigned long addr
)
251 if (addr
>= MPC826x_PCI_LOWER_MMIO
&&
252 addr
<= MPC826x_PCI_UPPER_MMIO
)
254 if (addr
>= MPC826x_PCI_LOWER_MEM
&&
255 addr
<= MPC826x_PCI_UPPER_MEM
)
260 #define is_pci_mem(pa) ( (pa > 0x80000000) && (pa < 0xc0000000))
261 int readb(volatile unsigned char *addr
)
264 unsigned long pa
= iopa((unsigned long) addr
);
269 idma_pci9_read((u8
*)&val
, (u8
*)pa
, sizeof(val
), sizeof(val
), 0);
273 int readw(volatile unsigned short *addr
)
276 unsigned long pa
= iopa((unsigned long) addr
);
279 return in_le16(addr
);
281 idma_pci9_read((u8
*)&val
, (u8
*)pa
, sizeof(val
), sizeof(val
), 0);
285 unsigned readl(volatile unsigned *addr
)
288 unsigned long pa
= iopa((unsigned long) addr
);
291 return in_le32(addr
);
293 idma_pci9_read((u8
*)&val
, (u8
*)pa
, sizeof(val
), sizeof(val
), 0);
297 int inb(unsigned port
)
300 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
302 idma_pci9_read((u8
*)&val
, (u8
*)addr
, sizeof(val
), sizeof(val
), 0);
306 int inw(unsigned port
)
309 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
311 idma_pci9_read((u8
*)&val
, (u8
*)addr
, sizeof(val
), sizeof(val
), 0);
315 unsigned inl(unsigned port
)
318 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
320 idma_pci9_read((u8
*)&val
, (u8
*)addr
, sizeof(val
), sizeof(val
), 0);
324 void insb(unsigned port
, void *buf
, int ns
)
326 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
328 idma_pci9_read((u8
*)buf
, (u8
*)addr
, ns
*sizeof(u8
), sizeof(u8
), 0);
331 void insw(unsigned port
, void *buf
, int ns
)
333 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
335 idma_pci9_read((u8
*)buf
, (u8
*)addr
, ns
*sizeof(u16
), sizeof(u16
), 0);
338 void insl(unsigned port
, void *buf
, int nl
)
340 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
342 idma_pci9_read((u8
*)buf
, (u8
*)addr
, nl
*sizeof(u32
), sizeof(u32
), 0);
345 void insw_ns(unsigned port
, void *buf
, int ns
)
347 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
349 idma_pci9_read((u8
*)buf
, (u8
*)addr
, ns
*sizeof(u16
), sizeof(u16
), 0);
352 void insl_ns(unsigned port
, void *buf
, int nl
)
354 u8
*addr
= (u8
*)(port
+ _IO_BASE
);
356 idma_pci9_read((u8
*)buf
, (u8
*)addr
, nl
*sizeof(u32
), sizeof(u32
), 0);
359 void *memcpy_fromio(void *dest
, unsigned long src
, size_t count
)
361 unsigned long pa
= iopa((unsigned long) src
);
364 idma_pci9_read((u8
*)dest
, (u8
*)pa
, count
, 32, 1);
366 memcpy(dest
, (void *)src
, count
);
370 EXPORT_SYMBOL(readb
);
371 EXPORT_SYMBOL(readw
);
372 EXPORT_SYMBOL(readl
);
379 EXPORT_SYMBOL(insw_ns
);
380 EXPORT_SYMBOL(insl_ns
);
381 EXPORT_SYMBOL(memcpy_fromio
);
383 #endif /* ifdef CONFIG_8260_PCI9 */
385 /* Indirect PCI routines adapted from arch/ppc/kernel/indirect_pci.c.
386 * Copyright (C) 1998 Gabriel Paubert.
388 #ifndef CONFIG_8260_PCI9
389 #define cfg_read(val, addr, type, op) *val = op((type)(addr))
391 #define cfg_read(val, addr, type, op) \
392 idma_pci9_read_le((u8*)(val),(u8*)(addr),sizeof(*(val)),sizeof(*(val)),0)
395 #define cfg_write(val, addr, type, op) op((type *)(addr), (val))
397 static int indirect_write_config(struct pci_bus
*pbus
, unsigned int devfn
, int where
,
400 struct pci_controller
*hose
= pbus
->sysdata
;
402 if (ppc_md
.pci_exclude_device
)
403 if (ppc_md
.pci_exclude_device(pbus
->number
, devfn
))
404 return PCIBIOS_DEVICE_NOT_FOUND
;
406 if (hose
->set_cfg_type
)
407 if (pbus
->number
!= hose
->first_busno
)
410 out_be32(hose
->cfg_addr
,
411 (((where
& 0xfc) | cfg_type
) << 24) | (devfn
<< 16)
412 | ((pbus
->number
- hose
->bus_offset
) << 8) | 0x80);
417 cfg_write(value
, hose
->cfg_data
+ (where
& 3), u8
, out_8
);
420 cfg_write(value
, hose
->cfg_data
+ (where
& 2), u16
, out_le16
);
423 cfg_write(value
, hose
->cfg_data
+ (where
& 0), u32
, out_le32
);
426 return PCIBIOS_SUCCESSFUL
;
429 static int indirect_read_config(struct pci_bus
*pbus
, unsigned int devfn
, int where
,
430 int size
, u32
*value
)
432 struct pci_controller
*hose
= pbus
->sysdata
;
434 if (ppc_md
.pci_exclude_device
)
435 if (ppc_md
.pci_exclude_device(pbus
->number
, devfn
))
436 return PCIBIOS_DEVICE_NOT_FOUND
;
438 if (hose
->set_cfg_type
)
439 if (pbus
->number
!= hose
->first_busno
)
442 out_be32(hose
->cfg_addr
,
443 (((where
& 0xfc) | cfg_type
) << 24) | (devfn
<< 16)
444 | ((pbus
->number
- hose
->bus_offset
) << 8) | 0x80);
449 cfg_read(value
, hose
->cfg_data
+ (where
& 3), u8
*, in_8
);
452 cfg_read(value
, hose
->cfg_data
+ (where
& 2), u16
*, in_le16
);
455 cfg_read(value
, hose
->cfg_data
+ (where
& 0), u32
*, in_le32
);
458 return PCIBIOS_SUCCESSFUL
;
461 static struct pci_ops indirect_pci_ops
=
463 .read
= indirect_read_config
,
464 .write
= indirect_write_config
,
468 setup_m8260_indirect_pci(struct pci_controller
* hose
, u32 cfg_addr
, u32 cfg_data
)
470 hose
->ops
= &indirect_pci_ops
;
471 hose
->cfg_addr
= (unsigned int *) ioremap(cfg_addr
, 4);
472 hose
->cfg_data
= (unsigned char *) ioremap(cfg_data
, 4);