blob: b00ad76ab8990557147b68721e2f481d1db98a84 [file] [log] [blame]
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +08001/*
2 * Support for indirect PCI bridges.
3 *
4 * Copyright (c) Freescale Semiconductor, Inc.
5 * 2006. All rights reserved.
6 *
7 * Jason Jin <Jason.jin@freescale.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * partly derived from
15 * arch/powerpc/platforms/86xx/mpc86xx_pcie.c
16 */
17
18#include <common.h>
19
20#ifdef CONFIG_PCI
21
22#include <asm/processor.h>
23#include <asm/io.h>
24#include <pci.h>
25
26#define PCI_CFG_OUT out_be32
27#define PEX_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff)
28
29static int
30indirect_read_config_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -050031 pci_dev_t dev,
32 int offset,
33 int len,
34 u32 *val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080035{
36 int bus = PCI_BUS(dev);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080037
Jon Loeliger1e43ac582006-08-22 10:42:21 -050038 volatile unsigned char *cfg_data;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080039 u32 temp;
40
41 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -050042 if (bus == 0xff) {
43 PCI_CFG_OUT(hose->cfg_addr,
44 dev | (offset & 0xfc) | 0x80000001);
45 } else {
46 PCI_CFG_OUT(hose->cfg_addr,
47 dev | (offset & 0xfc) | 0x80000000);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080048 }
49 /*
50 * Note: the caller has already checked that offset is
51 * suitably aligned and that len is 1, 2 or 4.
52 */
53 /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
54 cfg_data = hose->cfg_data;
55 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -050056 temp = in_le32((u32 *) cfg_data);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080057 switch (len) {
58 case 1:
Jon Loeligera1295442006-08-22 12:06:18 -050059 *val = (temp >> (((offset & 3)) * 8)) & 0xff;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080060 break;
61 case 2:
Jon Loeligera1295442006-08-22 12:06:18 -050062 *val = (temp >> (((offset & 3)) * 8)) & 0xffff;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080063 break;
64 default:
65 *val = temp;
66 break;
67 }
68
69 return 0;
70}
71
72static int
73indirect_write_config_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -050074 pci_dev_t dev,
75 int offset,
76 int len,
77 u32 val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080078{
79 int bus = PCI_BUS(dev);
Jon Loeliger1e43ac582006-08-22 10:42:21 -050080 volatile unsigned char *cfg_data;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080081 u32 temp;
82
83 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -050084 if (bus == 0xff) {
85 PCI_CFG_OUT(hose->cfg_addr,
86 dev | (offset & 0xfc) | 0x80000001);
87 } else {
88 PCI_CFG_OUT(hose->cfg_addr,
89 dev | (offset & 0xfc) | 0x80000000);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +080090 }
91
92 /*
93 * Note: the caller has already checked that offset is
94 * suitably aligned and that len is 1, 2 or 4.
95 */
96 /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
97 cfg_data = hose->cfg_data;
98 switch (len) {
99 case 1:
100 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -0500101 temp = in_le32((u32 *) cfg_data);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800102 temp = (temp & ~(0xff << ((offset & 3) * 8))) |
Jon Loeligera1295442006-08-22 12:06:18 -0500103 (val << ((offset & 3) * 8));
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800104 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -0500105 out_le32((u32 *) cfg_data, temp);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800106 break;
107 case 2:
108 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -0500109 temp = in_le32((u32 *) cfg_data);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800110 temp = (temp & ~(0xffff << ((offset & 3) * 8)));
Jon Loeligera1295442006-08-22 12:06:18 -0500111 temp |= (val << ((offset & 3) * 8));
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800112 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -0500113 out_le32((u32 *) cfg_data, temp);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800114 break;
115 default:
116 PEX_FIX;
Jon Loeligera1295442006-08-22 12:06:18 -0500117 out_le32((u32 *) cfg_data, val);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800118 break;
119 }
120 PEX_FIX;
121 return 0;
122}
123
124static int
125indirect_read_config_byte_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500126 pci_dev_t dev,
127 int offset,
128 u8 *val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800129{
130 u32 val32;
Jon Loeligera1295442006-08-22 12:06:18 -0500131 indirect_read_config_pcie(hose, dev, offset, 1, &val32);
132 *val = (u8) val32;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800133 return 0;
134}
135
136static int
137indirect_read_config_word_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500138 pci_dev_t dev,
139 int offset,
140 u16 *val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800141{
142 u32 val32;
Jon Loeligera1295442006-08-22 12:06:18 -0500143 indirect_read_config_pcie(hose, dev, offset, 2, &val32);
144 *val = (u16) val32;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800145 return 0;
146}
147
148static int
149indirect_read_config_dword_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500150 pci_dev_t dev,
151 int offset,
152 u32 *val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800153{
Jon Loeligera1295442006-08-22 12:06:18 -0500154 return indirect_read_config_pcie(hose, dev, offset, 4, val);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800155}
156
157static int
158indirect_write_config_byte_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500159 pci_dev_t dev,
160 int offset,
161 u8 val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800162{
Jon Loeligera1295442006-08-22 12:06:18 -0500163 return indirect_write_config_pcie(hose, dev, offset, 1, (u32) val);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800164}
165
166static int
167indirect_write_config_word_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500168 pci_dev_t dev,
169 int offset,
170 unsigned short val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800171{
Jon Loeligera1295442006-08-22 12:06:18 -0500172 return indirect_write_config_pcie(hose, dev, offset, 2, (u32) val);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800173}
174
175static int
176indirect_write_config_dword_pcie(struct pci_controller *hose,
Jon Loeligera1295442006-08-22 12:06:18 -0500177 pci_dev_t dev,
178 int offset,
179 u32 val)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800180{
Jon Loeligera1295442006-08-22 12:06:18 -0500181 return indirect_write_config_pcie(hose, dev, offset, 4, val);
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800182}
183
184void
Jon Loeligera1295442006-08-22 12:06:18 -0500185pcie_setup_indirect(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data)
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800186{
187 pci_set_ops(hose,
188 indirect_read_config_byte_pcie,
189 indirect_read_config_word_pcie,
190 indirect_read_config_dword_pcie,
191 indirect_write_config_byte_pcie,
192 indirect_write_config_word_pcie,
193 indirect_write_config_dword_pcie);
194
Jon Loeligera1295442006-08-22 12:06:18 -0500195 hose->cfg_addr = (unsigned int *)cfg_addr;
196 hose->cfg_data = (unsigned char *)cfg_data;
Jin Zhengxiong-R64188377d5962006-06-27 18:11:54 +0800197}
198
Jon Loeligera1295442006-08-22 12:06:18 -0500199#endif /* CONFIG_PCI */