diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/boot/dts/p1022ds.dtsi | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/p1022_ds.c | 106 |
2 files changed, 93 insertions, 29 deletions
diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi index 28c36377f9b9..c3344b04d8ff 100644 --- a/arch/powerpc/boot/dts/p1022ds.dtsi +++ b/arch/powerpc/boot/dts/p1022ds.dtsi | |||
@@ -33,22 +33,6 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | &board_lbc { | 35 | &board_lbc { |
36 | /* | ||
37 | * This node is used to access the pixis via "indirect" mode, | ||
38 | * which is done by writing the pixis register index to chip | ||
39 | * select 0 and the value to/from chip select 1. Indirect | ||
40 | * mode is the only way to access the pixis when DIU video | ||
41 | * is enabled. Note that this assumes that the first column | ||
42 | * of the 'ranges' property above is the chip select number. | ||
43 | */ | ||
44 | board-control@0,0 { | ||
45 | compatible = "fsl,p1022ds-indirect-pixis"; | ||
46 | reg = <0x0 0x0 1 /* CS0 */ | ||
47 | 0x1 0x0 1>; /* CS1 */ | ||
48 | interrupt-parent = <&mpic>; | ||
49 | interrupts = <8 0 0 0>; | ||
50 | }; | ||
51 | |||
52 | nor@0,0 { | 36 | nor@0,0 { |
53 | #address-cells = <1>; | 37 | #address-cells = <1>; |
54 | #size-cells = <1>; | 38 | #size-cells = <1>; |
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 74e310b4b460..b4437ca3d2c4 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <sysdev/fsl_pci.h> | 27 | #include <sysdev/fsl_pci.h> |
28 | #include <asm/udbg.h> | 28 | #include <asm/udbg.h> |
29 | #include <asm/fsl_guts.h> | 29 | #include <asm/fsl_guts.h> |
30 | #include <asm/fsl_lbc.h> | ||
30 | #include "smp.h" | 31 | #include "smp.h" |
31 | 32 | ||
32 | #include "mpc85xx.h" | 33 | #include "mpc85xx.h" |
@@ -142,17 +143,73 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, | |||
142 | { | 143 | { |
143 | } | 144 | } |
144 | 145 | ||
146 | struct fsl_law { | ||
147 | u32 lawbar; | ||
148 | u32 reserved1; | ||
149 | u32 lawar; | ||
150 | u32 reserved[5]; | ||
151 | }; | ||
152 | |||
153 | #define LAWBAR_MASK 0x00F00000 | ||
154 | #define LAWBAR_SHIFT 12 | ||
155 | |||
156 | #define LAWAR_EN 0x80000000 | ||
157 | #define LAWAR_TGT_MASK 0x01F00000 | ||
158 | #define LAW_TRGT_IF_LBC (0x04 << 20) | ||
159 | |||
160 | #define LAWAR_MASK (LAWAR_EN | LAWAR_TGT_MASK) | ||
161 | #define LAWAR_MATCH (LAWAR_EN | LAW_TRGT_IF_LBC) | ||
162 | |||
163 | #define BR_BA 0xFFFF8000 | ||
164 | |||
165 | /* | ||
166 | * Map a BRx value to a physical address | ||
167 | * | ||
168 | * The localbus BRx registers only store the lower 32 bits of the address. To | ||
169 | * obtain the upper four bits, we need to scan the LAW table. The entry which | ||
170 | * maps to the localbus will contain the upper four bits. | ||
171 | */ | ||
172 | static phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br) | ||
173 | { | ||
174 | #ifndef CONFIG_PHYS_64BIT | ||
175 | /* | ||
176 | * If we only have 32-bit addressing, then the BRx address *is* the | ||
177 | * physical address. | ||
178 | */ | ||
179 | return br & BR_BA; | ||
180 | #else | ||
181 | const struct fsl_law *law = ecm + 0xc08; | ||
182 | unsigned int i; | ||
183 | |||
184 | for (i = 0; i < count; i++) { | ||
185 | u64 lawbar = in_be32(&law[i].lawbar); | ||
186 | u32 lawar = in_be32(&law[i].lawar); | ||
187 | |||
188 | if ((lawar & LAWAR_MASK) == LAWAR_MATCH) | ||
189 | /* Extract the upper four bits */ | ||
190 | return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | #endif | ||
195 | } | ||
196 | |||
145 | /** | 197 | /** |
146 | * p1022ds_set_monitor_port: switch the output to a different monitor port | 198 | * p1022ds_set_monitor_port: switch the output to a different monitor port |
147 | * | ||
148 | */ | 199 | */ |
149 | static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) | 200 | static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) |
150 | { | 201 | { |
151 | struct device_node *guts_node; | 202 | struct device_node *guts_node; |
152 | struct device_node *indirect_node = NULL; | 203 | struct device_node *lbc_node = NULL; |
204 | struct device_node *law_node = NULL; | ||
153 | struct ccsr_guts __iomem *guts; | 205 | struct ccsr_guts __iomem *guts; |
206 | struct fsl_lbc_regs *lbc = NULL; | ||
207 | void *ecm = NULL; | ||
154 | u8 __iomem *lbc_lcs0_ba = NULL; | 208 | u8 __iomem *lbc_lcs0_ba = NULL; |
155 | u8 __iomem *lbc_lcs1_ba = NULL; | 209 | u8 __iomem *lbc_lcs1_ba = NULL; |
210 | phys_addr_t cs0_addr, cs1_addr; | ||
211 | const __be32 *iprop; | ||
212 | unsigned int num_laws; | ||
156 | u8 b; | 213 | u8 b; |
157 | 214 | ||
158 | /* Map the global utilities registers. */ | 215 | /* Map the global utilities registers. */ |
@@ -168,25 +225,43 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) | |||
168 | goto exit; | 225 | goto exit; |
169 | } | 226 | } |
170 | 227 | ||
171 | indirect_node = of_find_compatible_node(NULL, NULL, | 228 | lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); |
172 | "fsl,p1022ds-indirect-pixis"); | 229 | if (!lbc_node) { |
173 | if (!indirect_node) { | 230 | pr_err("p1022ds: missing localbus node\n"); |
174 | pr_err("p1022ds: missing pixis indirect mode node\n"); | ||
175 | goto exit; | 231 | goto exit; |
176 | } | 232 | } |
177 | 233 | ||
178 | lbc_lcs0_ba = of_iomap(indirect_node, 0); | 234 | lbc = of_iomap(lbc_node, 0); |
179 | if (!lbc_lcs0_ba) { | 235 | if (!lbc) { |
180 | pr_err("p1022ds: could not map localbus chip select 0\n"); | 236 | pr_err("p1022ds: could not map localbus node\n"); |
181 | goto exit; | 237 | goto exit; |
182 | } | 238 | } |
183 | 239 | ||
184 | lbc_lcs1_ba = of_iomap(indirect_node, 1); | 240 | law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law"); |
185 | if (!lbc_lcs1_ba) { | 241 | if (!law_node) { |
186 | pr_err("p1022ds: could not map localbus chip select 1\n"); | 242 | pr_err("p1022ds: missing local access window node\n"); |
187 | goto exit; | 243 | goto exit; |
188 | } | 244 | } |
189 | 245 | ||
246 | ecm = of_iomap(law_node, 0); | ||
247 | if (!ecm) { | ||
248 | pr_err("p1022ds: could not map local access window node\n"); | ||
249 | goto exit; | ||
250 | } | ||
251 | |||
252 | iprop = of_get_property(law_node, "fsl,num-laws", 0); | ||
253 | if (!iprop) { | ||
254 | pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); | ||
255 | goto exit; | ||
256 | } | ||
257 | num_laws = be32_to_cpup(iprop); | ||
258 | |||
259 | cs0_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[0].br)); | ||
260 | cs1_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[1].br)); | ||
261 | |||
262 | lbc_lcs0_ba = ioremap(cs0_addr, 1); | ||
263 | lbc_lcs1_ba = ioremap(cs1_addr, 1); | ||
264 | |||
190 | /* Make sure we're in indirect mode first. */ | 265 | /* Make sure we're in indirect mode first. */ |
191 | if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != | 266 | if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != |
192 | PMUXCR_ELBCDIU_DIU) { | 267 | PMUXCR_ELBCDIU_DIU) { |
@@ -254,10 +329,15 @@ exit: | |||
254 | iounmap(lbc_lcs1_ba); | 329 | iounmap(lbc_lcs1_ba); |
255 | if (lbc_lcs0_ba) | 330 | if (lbc_lcs0_ba) |
256 | iounmap(lbc_lcs0_ba); | 331 | iounmap(lbc_lcs0_ba); |
332 | if (lbc) | ||
333 | iounmap(lbc); | ||
334 | if (ecm) | ||
335 | iounmap(ecm); | ||
257 | if (guts) | 336 | if (guts) |
258 | iounmap(guts); | 337 | iounmap(guts); |
259 | 338 | ||
260 | of_node_put(indirect_node); | 339 | of_node_put(law_node); |
340 | of_node_put(lbc_node); | ||
261 | of_node_put(guts_node); | 341 | of_node_put(guts_node); |
262 | } | 342 | } |
263 | 343 | ||